a6ba2b44c5b0faf5b747f3262dfed0a8d2fbb180
[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        "/opt/usr/data/network/"
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_supported = 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                         DBG("field: %s, value: %s", field, value);
91
92                         if (value != NULL) {
93                                 fprintf (fp, "eap=%s\n", value);
94                                 eapol.eap_type = g_strdup(value);
95                         }
96                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_IDENTITY) == 0) {
97                         DBG("field: %s, value: %s", field, value);
98
99                         if (value != NULL) {
100                                 fprintf (fp, "identity=\"%s\"\n", value);
101                                 eapol.identity = g_strdup(value);
102                         }
103                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_ANONYMOUS_IDENTITY) == 0) {
104                         DBG("field: %s, value: %s", field, value);
105
106                         if (value != NULL) {
107                                 fprintf (fp, "anonymous_identity=\"%s\"\n", value);
108                                 eapol.anonymous_identity = g_strdup(value);
109                         }
110                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PASSPHRASE) == 0) {
111                         DBG("field: %s, value: %s", field, value);
112
113                         if (value != NULL)
114                                 fprintf (fp, "password=\"%s\"\n", value);
115                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CA_CERT_FILE) == 0) {
116                         DBG("field: %s, value: %s", field, value);
117
118                         if (value != NULL) {
119                                 fprintf (fp, "ca_cert=\"%s\"\n", value);
120                                 eapol.ca_cert_file = g_strdup(value);
121                         }
122                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_CLIENT_CERT_FILE) == 0) {
123                         DBG("field: %s, value: %s", field, value);
124
125                         if (value != NULL) {
126                                 fprintf (fp, "client_cert=\"%s\"\n", value);
127                                 eapol.client_cert_file = g_strdup(value);
128                         }
129                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_FILE) == 0) {
130                         DBG("field: %s, value: %s", field, value);
131
132                         if (value != NULL) {
133                                 fprintf (fp, "private_key=\"%s\"\n", value);
134                                 eapol.private_key_file = g_strdup(value);
135                         }
136                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PVT_KEY_PASSPHRASE) == 0) {
137                         DBG("field: %s, value: %s", field, value);
138
139                         if (value != NULL) {
140                                 fprintf (fp, "private_key_passwd=\"%s\"\n", value);
141                                 eapol.private_key_password = g_strdup(value);
142                         }
143                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PAC_FILE) == 0) {
144                         DBG("field: %s, value: %s", field, value);
145
146                         if (value != NULL) {
147                                 fprintf (fp, "pac_file=\"%s\"\n", value);
148                                 eapol.pac_file = g_strdup(value);
149                         }
150                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE2) == 0) {
151                         DBG("field: %s, value: %s", field, value);
152
153                         if (value != NULL) {
154                                 char str[50] = {0,};
155                                 sprintf(str, "auth=%s", value);
156                                 fprintf (fp, "phase2=\"%s\"\n", str);
157
158                                 eapol.phase2 = g_strdup(value);
159                         }
160                 } else if (g_strcmp0(field, CONNMAN_CONFIG_FIELD_PHASE1) == 0) {
161                         DBG("field: %s, value: %s", field, value);
162
163                         if (value != NULL) {
164                                 int peap_version;
165                                 char str[50] = {0,};
166                                 if ((g_strcmp0(value, "VERSION_AUTO") == 0) ||
167                                                 (g_strcmp0(value, "VERSION_0") == 0))
168                                         peap_version = 0;
169                                 else
170                                         peap_version = 1;
171
172                                 sprintf(str, "peapver=%d", peap_version);
173                                 fprintf (fp, "phase1=\"%s\"\n", str);
174                                 eapol.phase1 = peap_version;
175                         }
176                 }
177         }
178
179         fprintf (fp, "}");      /* closing of conf file */
180         fflush(fp);
181         fclose(fp);
182 out:
183         g_free(filename);
184
185         return err;
186 }
187
188 static void __netconfig_cleanup_eapol()
189 {
190         g_free(eapol.eap_type);
191         g_free(eapol.identity);
192         g_free(eapol.anonymous_identity);
193         g_free(eapol.ca_cert_file);
194         g_free(eapol.client_cert_file);
195         g_free(eapol.private_key_file);
196         g_free(eapol.private_key_password);
197         g_free(eapol.pac_file);
198         g_free(eapol.phase2);
199         eapol.phase1 = -1;
200 }
201
202 static int __netconfig_set_eapol_property(const gchar *service, gboolean use_eapol)
203 {
204         GVariant *params = NULL;
205         GVariant *message = NULL;
206         GVariantBuilder *builder;
207
208         const char *prop_eap_on_ethernet = "EapOverEthernet";
209
210         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
211
212         g_variant_builder_add(builder, "{sv}", "UseEapol", g_variant_new_boolean(use_eapol));
213
214         if (use_eapol) {
215                 if (eapol.eap_type)
216                         g_variant_builder_add(builder, "{sv}", "EAP",
217                                         g_variant_new_string(eapol.eap_type));
218                 if (eapol.identity)
219                         g_variant_builder_add(builder, "{sv}", "Identity",
220                                         g_variant_new_string(eapol.identity));
221                 if (eapol.anonymous_identity)
222                         g_variant_builder_add(builder, "{sv}", "AnonymousIdentity",
223                                         g_variant_new_string(eapol.anonymous_identity));
224                 if (eapol.ca_cert_file)
225                         g_variant_builder_add(builder, "{sv}", "CACertFile",
226                                         g_variant_new_string(eapol.ca_cert_file));
227                 if (eapol.client_cert_file)
228                         g_variant_builder_add(builder, "{sv}", "ClientCertFile",
229                                         g_variant_new_string(eapol.client_cert_file));
230                 if (eapol.private_key_file)
231                         g_variant_builder_add(builder, "{sv}", "PrivateKeyFile",
232                                         g_variant_new_string(eapol.private_key_file));
233                 if (eapol.private_key_password)
234                         g_variant_builder_add(builder, "{sv}", "PrivateKeyPassphrase",
235                                         g_variant_new_string(eapol.private_key_password));
236                 if (eapol.phase2)
237                         g_variant_builder_add(builder, "{sv}", "Phase2",
238                                         g_variant_new_string(eapol.phase2));
239
240                 if (eapol.phase1 >= 0)
241                         g_variant_builder_add(builder, "{sv}", "Phase1",
242                                         g_variant_new_int32(eapol.phase1));
243
244                 if (eapol.pac_file)
245                         g_variant_builder_add(builder, "{sv}", "PacFile",
246                                         g_variant_new_string(eapol.pac_file));
247
248                 __netconfig_cleanup_eapol();
249         }
250
251         params = g_variant_new("(sv)", prop_eap_on_ethernet, g_variant_builder_end(builder));
252         g_variant_builder_unref(builder);
253
254         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE, service,
255                         CONNMAN_SERVICE_INTERFACE, "SetProperty", params);
256         if (message == NULL) {
257                 g_variant_unref(message);
258                 return -1;
259         }
260
261         g_variant_unref(message);
262
263         return 0;
264 }
265
266 /*********************
267  * Handler Functions *
268  ********************/
269
270 gboolean handle_enable_eap(Ethernet *object, GDBusMethodInvocation *invocation,
271                            const gchar *service, gboolean enable)
272 {
273         g_return_val_if_fail(object != NULL, TRUE);
274
275         DBG("%s EAPoL", enable ? "enable" : "disable");
276
277         if (netconfig_is_ethernet_profile(service) != TRUE) {
278                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
279                 return TRUE;
280         }
281
282         /* TODO: Execute WPA Supplicant if not running */
283         __execute_supplicant(enable);
284
285         /* TODO: Make below variable interface specific and set
286         connMan profile associated with this interface as EAP enabled.
287         */
288         g_eap_supported = enable;
289
290         if (enable == false) {
291                 int err = __netconfig_set_eapol_property(service, false);
292                 if (err < 0) {
293                         ERR("Failed to set eapol property.");
294                         netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
295                         return TRUE;
296                 }
297         }
298
299         ethernet_complete_enable_eap(object, invocation);
300         return TRUE;
301 }
302
303 gboolean handle_is_eap_supported(Ethernet *object, GDBusMethodInvocation *invocation)
304 {
305         g_return_val_if_fail(object != NULL, TRUE);
306
307         DBG("handle_is_eap_supported");
308         gboolean value = FALSE;
309
310         value = g_eap_supported;
311
312         ethernet_complete_is_eap_supported(object, invocation, value);
313         return TRUE;
314 }
315
316 gboolean handle_set_eap_config(Ethernet *object, GDBusMethodInvocation *invocation,
317                         const gchar *service, GVariant *fields)
318 {
319         g_return_val_if_fail(object != NULL, TRUE);
320
321         DBG("handle_set_eap_config for service [%s]", service);
322
323         if (netconfig_is_ethernet_profile(service) != TRUE) {
324                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_WRONG_PROFILE, "InvalidService");
325                 return TRUE;
326         }
327
328         if (g_eap_supported == FALSE) {
329                 netconfig_error_dbus_method_return(invocation,
330                                                    NETCONFIG_ERROR_INTERNAL,
331                                                    "EapNotEnabled");
332                 return TRUE;
333         }
334
335         /** Create conf file */
336         int err = __netconfig_set_eap_config_file(fields);
337         if (err < 0) {
338                 ERR("Failed to save eapol conf file.");
339                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
340                 return TRUE;
341         }
342
343         err = __netconfig_set_eapol_property(service, true);
344         if (err < 0) {
345                 ERR("Failed to set eapol property.");
346                 netconfig_error_dbus_method_return(invocation, NETCONFIG_ERROR_INTERNAL, "InternalError");
347                 return TRUE;
348         }
349
350         ethernet_complete_set_eap_config(object, invocation);
351         return TRUE;
352 }
353
354 /*****************************
355  * Initializations Functions *
356  ****************************/
357 void ethernet_object_create_and_init(void)
358 {
359         DBG("Create ethernet object.");
360         GDBusInterfaceSkeleton *interface_ethernet = NULL;
361         GDBusConnection *connection = NULL;
362         GDBusObjectManagerServer *server = netdbus_get_ethernet_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         ethernet_object = ethernet_skeleton_new();
371         interface_ethernet = G_DBUS_INTERFACE_SKELETON(ethernet_object);
372
373         /* EAP over Ethernet Service */
374         g_signal_connect(ethernet_object, "handle-enable-eap",
375                         G_CALLBACK(handle_enable_eap), NULL);
376         g_signal_connect(ethernet_object, "handle-is-eap-supported",
377                         G_CALLBACK(handle_is_eap_supported), NULL);
378         g_signal_connect(ethernet_object, "handle-set-eap-config",
379                         G_CALLBACK(handle_set_eap_config), NULL);
380
381         if (!g_dbus_interface_skeleton_export(interface_ethernet, connection,
382                         NETCONFIG_ETHERNET_PATH, NULL)) {
383                 ERR("Export NETCONFIG_ETHERNET_PATH for ethernet failed");
384         }
385
386         return;
387 }
388
389 void ethernet_object_deinit(void)
390 {
391         DBG("Deinit ethernet object.");
392
393         g_object_unref(ethernet_object);
394 }