5 * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
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.
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.
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
32 #include <sys/inotify.h>
36 #include <connman/provision.h>
37 #include <connman/ipaddress.h>
40 struct connman_config_service {
45 unsigned int ssid_len;
48 char *anonymous_identity;
51 char *altsubject_match;
52 char *domain_suffix_match;
54 char *client_cert_file;
55 char *private_key_file;
56 char *private_key_passphrase;
57 char *private_key_passphrase_type;
60 enum connman_service_security security;
61 GSList *service_identifiers;
62 char *config_ident; /* file prefix */
63 char *config_entry; /* entry name */
71 unsigned char ipv6_prefix_length;
78 char **search_domains;
88 struct connman_config {
92 GHashTable *service_table;
95 static GHashTable *config_table = NULL;
97 static bool cleanup = false;
99 /* Definition of possible strings in the .config files */
100 #define CONFIG_KEY_NAME "Name"
101 #define CONFIG_KEY_DESC "Description"
103 #define SERVICE_KEY_TYPE "Type"
104 #define SERVICE_KEY_NAME "Name"
105 #define SERVICE_KEY_SSID "SSID"
106 #define SERVICE_KEY_EAP "EAP"
107 #define SERVICE_KEY_CA_CERT "CACertFile"
108 #define SERVICE_KEY_CL_CERT "ClientCertFile"
109 #define SERVICE_KEY_PRV_KEY "PrivateKeyFile"
110 #define SERVICE_KEY_PRV_KEY_PASS "PrivateKeyPassphrase"
111 #define SERVICE_KEY_PRV_KEY_PASS_TYPE "PrivateKeyPassphraseType"
112 #define SERVICE_KEY_IDENTITY "Identity"
113 #define SERVICE_KEY_ANONYMOUS_IDENTITY "AnonymousIdentity"
114 #define SERVICE_KEY_SUBJECT_MATCH "SubjectMatch"
115 #define SERVICE_KEY_ALT_SUBJECT_MATCH "AltSubjectMatch"
116 #define SERVICE_KEY_DOMAIN_SUFF_MATCH "DomainSuffixMatch"
117 #define SERVICE_KEY_DOMAIN_MATCH "DomainMatch"
118 #define SERVICE_KEY_PHASE2 "Phase2"
119 #define SERVICE_KEY_PASSPHRASE "Passphrase"
120 #define SERVICE_KEY_SECURITY "Security"
121 #define SERVICE_KEY_HIDDEN "Hidden"
122 #define SERVICE_KEY_MDNS "mDNS"
124 #define SERVICE_KEY_IPv4 "IPv4"
125 #define SERVICE_KEY_IPv6 "IPv6"
126 #define SERVICE_KEY_IPv6_PRIVACY "IPv6.Privacy"
127 #define SERVICE_KEY_MAC "MAC"
128 #define SERVICE_KEY_DEVICE_NAME "DeviceName"
129 #define SERVICE_KEY_NAMESERVERS "Nameservers"
130 #define SERVICE_KEY_SEARCH_DOMAINS "SearchDomains"
131 #define SERVICE_KEY_TIMESERVERS "Timeservers"
132 #define SERVICE_KEY_DOMAIN "Domain"
133 #if defined TIZEN_EXT
134 #define SERVICE_KEY_CONNECTOR "Connector"
135 #define SERVICE_KEY_C_SIGN_KEY "CSignKey"
136 #define SERVICE_KEY_NET_ACCESS_KEY "NetAccessKey"
139 static const char *config_possible_keys[] = {
145 static const char *service_possible_keys[] = {
153 SERVICE_KEY_PRV_KEY_PASS,
154 SERVICE_KEY_PRV_KEY_PASS_TYPE,
155 SERVICE_KEY_IDENTITY,
156 SERVICE_KEY_ANONYMOUS_IDENTITY,
157 SERVICE_KEY_SUBJECT_MATCH,
158 SERVICE_KEY_ALT_SUBJECT_MATCH,
159 SERVICE_KEY_DOMAIN_SUFF_MATCH,
160 SERVICE_KEY_DOMAIN_MATCH,
162 SERVICE_KEY_PASSPHRASE,
163 SERVICE_KEY_SECURITY,
167 SERVICE_KEY_IPv6_PRIVACY,
169 SERVICE_KEY_DEVICE_NAME,
171 SERVICE_KEY_NAMESERVERS,
172 SERVICE_KEY_SEARCH_DOMAINS,
173 SERVICE_KEY_TIMESERVERS,
175 #if defined TIZEN_EXT
176 SERVICE_KEY_CONNECTOR,
177 SERVICE_KEY_C_SIGN_KEY,
178 SERVICE_KEY_NET_ACCESS_KEY,
183 static void unregister_config(gpointer data)
185 struct connman_config *config = data;
187 connman_info("Removing configuration %s", config->ident);
189 g_hash_table_destroy(config->service_table);
191 g_free(config->description);
192 g_free(config->name);
193 g_free(config->ident);
197 static void unregister_service(gpointer data)
199 struct connman_config_service *config_service = data;
200 struct connman_service *service;
207 connman_info("Removing service configuration %s",
208 config_service->ident);
210 if (config_service->virtual)
213 for (list = config_service->service_identifiers; list;
215 service_id = list->data;
217 service = connman_service_lookup_from_identifier(service_id);
219 __connman_service_set_immutable(service, false);
220 __connman_service_set_config(service, NULL, NULL);
221 __connman_service_remove(service);
224 * Ethernet or gadget service cannot be removed by
225 * __connman_service_remove() so reset the ipconfig
228 if (connman_service_get_type(service) ==
229 CONNMAN_SERVICE_TYPE_ETHERNET ||
230 connman_service_get_type(service) ==
231 CONNMAN_SERVICE_TYPE_GADGET) {
232 __connman_service_disconnect(service);
233 __connman_service_reset_ipconfig(service,
234 CONNMAN_IPCONFIG_TYPE_IPV4, NULL, NULL);
235 __connman_service_reset_ipconfig(service,
236 CONNMAN_IPCONFIG_TYPE_IPV6, NULL, NULL);
237 __connman_service_set_ignore(service, true);
240 * After these operations, user needs to
241 * reconnect ethernet cable to get IP
247 if (!__connman_storage_remove_service(service_id))
248 DBG("Could not remove all files for service %s",
253 g_free(config_service->ident);
254 g_free(config_service->type);
255 g_free(config_service->name);
256 g_free(config_service->ssid);
257 g_free(config_service->eap);
258 g_free(config_service->identity);
259 g_free(config_service->anonymous_identity);
260 g_free(config_service->ca_cert_file);
261 g_free(config_service->subject_match);
262 g_free(config_service->altsubject_match);
263 g_free(config_service->domain_suffix_match);
264 g_free(config_service->domain_match);
265 g_free(config_service->client_cert_file);
266 g_free(config_service->private_key_file);
267 g_free(config_service->private_key_passphrase);
268 g_free(config_service->private_key_passphrase_type);
269 g_free(config_service->phase2);
270 g_free(config_service->passphrase);
271 g_free(config_service->ipv4_address);
272 g_free(config_service->ipv4_gateway);
273 g_free(config_service->ipv4_netmask);
274 g_free(config_service->ipv6_address);
275 g_free(config_service->ipv6_gateway);
276 g_free(config_service->ipv6_privacy);
277 g_free(config_service->mac);
278 g_free(config_service->devname);
279 g_strfreev(config_service->nameservers);
280 g_strfreev(config_service->search_domains);
281 g_strfreev(config_service->timeservers);
282 g_free(config_service->domain_name);
283 g_slist_free_full(config_service->service_identifiers, g_free);
284 g_free(config_service->config_ident);
285 g_free(config_service->config_entry);
286 g_free(config_service->virtual_file);
287 #if defined TIZEN_EXT
288 g_free(config_service->connector);
289 g_free(config_service->c_sign_key);
290 g_free(config_service->net_access_key);
292 g_free(config_service);
295 static void check_keys(GKeyFile *keyfile, const char *group,
296 const char **possible_keys)
299 gsize nb_avail_keys, i, j;
301 avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
306 * For each key in the configuration file,
307 * verify it is understood by connman
309 for (i = 0 ; i < nb_avail_keys; i++) {
310 for (j = 0; possible_keys[j] ; j++)
311 if (g_strcmp0(avail_keys[i], possible_keys[j]) == 0)
314 if (!possible_keys[j])
315 connman_warn("Unknown configuration key %s in [%s]",
316 avail_keys[i], group);
319 g_strfreev(avail_keys);
322 static int check_family(const char *address, int expected_family)
327 family = connman_inet_check_ipaddress(address);
329 DBG("Cannot get address family of %s (%d/%s)", address,
330 family, gai_strerror(family));
337 if (expected_family != AF_INET) {
338 DBG("Wrong type address %s, expecting IPv4", address);
344 if (expected_family != AF_INET6) {
345 DBG("Wrong type address %s, expecting IPv6", address);
351 DBG("Unsupported address family %d", family);
360 static int parse_address(const char *address_str, int address_family,
361 char **address, char **netmask, char **gateway)
363 char *addr_str, *mask_str, *gw_str;
367 route = g_strsplit(address_str, "/", 0);
372 if (!addr_str || addr_str[0] == '\0') {
377 if ((err = check_family(addr_str, address_family)) < 0)
381 if (!mask_str || mask_str[0] == '\0') {
387 if (gw_str && gw_str[0]) {
388 if ((err = check_family(gw_str, address_family)) < 0)
393 *address = g_strdup(addr_str);
396 *netmask = g_strdup(mask_str);
399 *gateway = g_strdup(gw_str);
402 DBG("address %s/%s via %s", *address, *netmask, *gateway);
404 DBG("address %s/%s", *address, *netmask);
412 static bool check_address(char *address_str, char **address)
414 if (g_ascii_strcasecmp(address_str, "auto") == 0 ||
415 g_ascii_strcasecmp(address_str, "dhcp") == 0 ||
416 g_ascii_strcasecmp(address_str, "off") == 0) {
417 *address = address_str;
424 static bool load_service_generic(GKeyFile *keyfile,
425 const char *group, struct connman_config *config,
426 struct connman_config_service *service)
432 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_IPv4, NULL);
433 if (str && check_address(str, &service->ipv4_address)) {
436 if (parse_address(str, AF_INET, &service->ipv4_address,
437 &mask, &service->ipv4_gateway) < 0) {
438 connman_warn("Invalid format for IPv4 address %s",
444 if (!g_strrstr(mask, ".")) {
445 /* We have netmask length */
447 struct in_addr netmask_in;
448 unsigned char prefix_len = 32;
450 long int value = strtol(mask, &ptr, 10);
452 if (ptr != mask && *ptr == '\0' && value && value <= 32)
455 addr = 0xffffffff << (32 - prefix_len);
456 netmask_in.s_addr = htonl(addr);
457 service->ipv4_netmask =
458 g_strdup(inet_ntoa(netmask_in));
462 service->ipv4_netmask = mask;
467 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_IPv6, NULL);
468 if (str && check_address(str, &service->ipv6_address)) {
474 if (parse_address(str, AF_INET6, &service->ipv6_address,
475 &mask, &service->ipv6_gateway) < 0) {
476 connman_warn("Invalid format for IPv6 address %s",
482 value = strtol(mask, &ptr, 10);
483 if (ptr != mask && *ptr == '\0' && value <= 128)
484 service->ipv6_prefix_length = value;
486 service->ipv6_prefix_length = 128;
492 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_IPv6_PRIVACY,
495 g_free(service->ipv6_privacy);
496 service->ipv6_privacy = str;
499 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_MAC, NULL);
501 g_free(service->mac);
505 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DEVICE_NAME, NULL);
507 g_free(service->devname);
508 service->devname = str;
511 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DOMAIN, NULL);
513 g_free(service->domain_name);
514 service->domain_name = str;
517 strlist = __connman_config_get_string_list(keyfile, group,
518 SERVICE_KEY_NAMESERVERS,
522 g_strfreev(service->nameservers);
523 service->nameservers = strlist;
528 strlist = __connman_config_get_string_list(keyfile, group,
529 SERVICE_KEY_SEARCH_DOMAINS,
533 g_strfreev(service->search_domains);
534 service->search_domains = strlist;
539 strlist = __connman_config_get_string_list(keyfile, group,
540 SERVICE_KEY_TIMESERVERS,
544 g_strfreev(service->timeservers);
545 service->timeservers = strlist;
550 service->mdns = __connman_config_get_bool(keyfile, group,
551 SERVICE_KEY_MDNS, NULL);
556 g_free(service->ident);
557 g_free(service->type);
558 g_free(service->ipv4_address);
559 g_free(service->ipv4_netmask);
560 g_free(service->ipv4_gateway);
561 g_free(service->ipv6_address);
562 g_free(service->ipv6_gateway);
563 g_free(service->mac);
564 g_free(service->devname);
570 static bool load_service(GKeyFile *keyfile, const char *group,
571 struct connman_config *config)
573 struct connman_config_service *service;
575 char *str, *hex_ssid;
576 enum connman_service_security security;
577 bool service_created = false;
579 /* Strip off "service_" prefix */
582 if (strlen(ident) < 1)
585 /* Verify that provided keys are good */
586 check_keys(keyfile, group, service_possible_keys);
588 service = g_hash_table_lookup(config->service_table, ident);
590 service = g_try_new0(struct connman_config_service, 1);
594 service->ident = g_strdup(ident);
596 service_created = true;
599 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_TYPE, NULL);
601 g_free(service->type);
604 connman_warn("Type of the configured service is missing "
605 "for group %s", group);
609 if (!load_service_generic(keyfile, group, config, service))
612 if (g_strcmp0(str, "ethernet") == 0) {
613 service->config_ident = g_strdup(config->ident);
614 service->config_entry = g_strdup_printf("service_%s",
617 g_hash_table_insert(config->service_table, service->ident,
622 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_NAME, NULL);
624 g_free(service->name);
628 hex_ssid = __connman_config_get_string(keyfile, group, SERVICE_KEY_SSID,
632 unsigned int i, j = 0, hex;
633 size_t hex_ssid_len = strlen(hex_ssid);
635 ssid = g_try_malloc0(hex_ssid_len / 2);
641 for (i = 0; i < hex_ssid_len; i += 2) {
642 if (sscanf(hex_ssid + i, "%02x", &hex) <= 0) {
643 connman_warn("Invalid SSID %s", hex_ssid);
653 g_free(service->ssid);
654 service->ssid = ssid;
655 service->ssid_len = hex_ssid_len / 2;
656 } else if (service->name) {
658 unsigned int ssid_len;
660 ssid_len = strlen(service->name);
661 #if defined TIZEN_EXT
662 ssid = g_try_malloc0(ssid_len + 1);
664 ssid = g_try_malloc0(ssid_len);
669 memcpy(ssid, service->name, ssid_len);
670 g_free(service->ssid);
671 service->ssid = ssid;
672 service->ssid_len = ssid_len;
675 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_EAP, NULL);
677 g_free(service->eap);
681 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_CA_CERT, NULL);
683 g_free(service->ca_cert_file);
684 service->ca_cert_file = str;
687 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_CL_CERT, NULL);
689 g_free(service->client_cert_file);
690 service->client_cert_file = str;
693 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_PRV_KEY, NULL);
695 g_free(service->private_key_file);
696 service->private_key_file = str;
699 str = __connman_config_get_string(keyfile, group,
700 SERVICE_KEY_PRV_KEY_PASS, NULL);
702 g_free(service->private_key_passphrase);
703 service->private_key_passphrase = str;
706 str = __connman_config_get_string(keyfile, group,
707 SERVICE_KEY_PRV_KEY_PASS_TYPE, NULL);
709 g_free(service->private_key_passphrase_type);
710 service->private_key_passphrase_type = str;
713 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_IDENTITY, NULL);
715 g_free(service->identity);
716 service->identity = str;
719 str = __connman_config_get_string(keyfile, group,
720 SERVICE_KEY_ANONYMOUS_IDENTITY, NULL);
722 g_free(service->anonymous_identity);
723 service->anonymous_identity = str;
726 str = __connman_config_get_string(keyfile, group,
727 SERVICE_KEY_SUBJECT_MATCH, NULL);
729 g_free(service->subject_match);
730 service->subject_match = str;
733 str = __connman_config_get_string(keyfile, group,
734 SERVICE_KEY_ALT_SUBJECT_MATCH, NULL);
736 g_free(service->altsubject_match);
737 service->altsubject_match = str;
740 str = __connman_config_get_string(keyfile, group,
741 SERVICE_KEY_DOMAIN_SUFF_MATCH, NULL);
743 g_free(service->domain_suffix_match);
744 service->domain_suffix_match = str;
747 str = __connman_config_get_string(keyfile, group,
748 SERVICE_KEY_DOMAIN_MATCH, NULL);
750 g_free(service->domain_match);
751 service->domain_match = str;
754 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_PHASE2, NULL);
756 g_free(service->phase2);
757 service->phase2 = str;
760 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_PASSPHRASE,
763 g_free(service->passphrase);
764 service->passphrase = str;
766 #if defined TIZEN_EXT
768 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_CONNECTOR,
771 g_free(service->connector);
772 service->connector = str;
775 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_C_SIGN_KEY,
778 g_free(service->c_sign_key);
779 service->c_sign_key = str;
782 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_NET_ACCESS_KEY,
785 g_free(service->net_access_key);
786 service->net_access_key = str;
790 str = __connman_config_get_string(keyfile, group, SERVICE_KEY_SECURITY,
792 security = __connman_service_string2security(str);
796 if (str && security != CONNMAN_SERVICE_SECURITY_8021X)
797 connman_info("Mismatch between EAP configuration and "
799 SERVICE_KEY_SECURITY, str);
801 service->security = CONNMAN_SERVICE_SECURITY_8021X;
803 } else if (service->passphrase) {
806 if (security == CONNMAN_SERVICE_SECURITY_PSK ||
807 #if defined TIZEN_EXT
808 security == CONNMAN_SERVICE_SECURITY_RSN ||
809 security == CONNMAN_SERVICE_SECURITY_SAE ||
811 security == CONNMAN_SERVICE_SECURITY_WEP) {
812 service->security = security;
814 connman_info("Mismatch with passphrase and "
816 SERVICE_KEY_SECURITY, str);
819 CONNMAN_SERVICE_SECURITY_PSK;
823 service->security = CONNMAN_SERVICE_SECURITY_PSK;
824 #if defined TIZEN_EXT
825 } else if (service->connector) {
827 if (str && security != CONNMAN_SERVICE_SECURITY_DPP)
828 connman_info("Mismatch between DPP configuration and "
830 SERVICE_KEY_SECURITY, str);
832 service->security = CONNMAN_SERVICE_SECURITY_DPP;
836 if (security != CONNMAN_SERVICE_SECURITY_NONE)
837 connman_info("Mismatch no security and "
839 SERVICE_KEY_SECURITY, str);
841 service->security = CONNMAN_SERVICE_SECURITY_NONE;
843 service->security = CONNMAN_SERVICE_SECURITY_NONE;
847 service->config_ident = g_strdup(config->ident);
848 service->config_entry = g_strdup_printf("service_%s", service->ident);
850 service->hidden = __connman_config_get_bool(keyfile, group,
851 SERVICE_KEY_HIDDEN, NULL);
854 g_hash_table_insert(config->service_table, service->ident,
857 connman_info("Adding service configuration %s", service->ident);
862 if (service_created) {
863 g_free(service->ident);
864 g_free(service->type);
865 g_free(service->name);
866 g_free(service->ssid);
873 static bool load_service_from_keyfile(GKeyFile *keyfile,
874 struct connman_config *config)
880 groups = g_key_file_get_groups(keyfile, NULL);
882 for (i = 0; groups[i]; i++) {
883 if (!g_str_has_prefix(groups[i], "service_")) {
884 connman_warn("Ignore group named '%s' because prefix "
885 "is not 'service_'", groups[i]);
888 if (load_service(keyfile, groups[i], config))
897 static int load_config(struct connman_config *config)
902 DBG("config %p", config);
904 keyfile = __connman_storage_load_config(config->ident);
908 g_key_file_set_list_separator(keyfile, ',');
910 /* Verify keys validity of the global section */
911 check_keys(keyfile, "global", config_possible_keys);
913 str = __connman_config_get_string(keyfile, "global", CONFIG_KEY_NAME, NULL);
915 g_free(config->name);
919 str = __connman_config_get_string(keyfile, "global", CONFIG_KEY_DESC, NULL);
921 g_free(config->description);
922 config->description = str;
925 if (!load_service_from_keyfile(keyfile, config))
926 connman_warn("Config file %s/%s.config does not contain any "
927 "configuration that can be provisioned!",
928 STORAGEDIR, config->ident);
930 g_key_file_free(keyfile);
935 static struct connman_config *create_config(const char *ident)
937 struct connman_config *config;
939 DBG("ident %s", ident);
941 if (g_hash_table_lookup(config_table, ident))
944 config = g_try_new0(struct connman_config, 1);
948 config->ident = g_strdup(ident);
950 config->service_table = g_hash_table_new_full(g_str_hash, g_str_equal,
951 NULL, unregister_service);
953 g_hash_table_insert(config_table, config->ident, config);
955 connman_info("Adding configuration %s", config->ident);
960 static bool validate_ident(const char *ident)
967 for (i = 0; i < strlen(ident); i++)
968 if (!g_ascii_isprint(ident[i]))
974 static int read_configs(void)
980 dir = g_dir_open(STORAGEDIR, 0, NULL);
984 while ((file = g_dir_read_name(dir))) {
988 if (!g_str_has_suffix(file, ".config"))
991 ident = g_strrstr(file, ".config");
995 str = g_string_new_len(file, ident - file);
999 ident = g_string_free(str, FALSE);
1001 if (validate_ident(ident)) {
1002 struct connman_config *config;
1004 config = create_config(ident);
1006 load_config(config);
1008 connman_error("Invalid config ident %s", ident);
1019 static void config_notify_handler(struct inotify_event *event,
1027 if (!g_str_has_suffix(ident, ".config"))
1030 ext = g_strrstr(ident, ".config");
1036 if (!validate_ident(ident)) {
1037 connman_error("Invalid config ident %s", ident);
1041 if (event->mask & (IN_CREATE | IN_MOVED_TO))
1042 create_config(ident);
1044 if (event->mask & (IN_MODIFY | IN_MOVED_TO)) {
1045 struct connman_config *config;
1047 config = g_hash_table_lookup(config_table, ident);
1051 g_hash_table_remove_all(config->service_table);
1052 load_config(config);
1053 ret = __connman_service_provision_changed(ident);
1056 * Re-scan the config file for any
1059 g_hash_table_remove_all(config->service_table);
1060 load_config(config);
1061 __connman_service_provision_changed(ident);
1066 if (event->mask & (IN_DELETE | IN_MOVED_FROM))
1067 g_hash_table_remove(config_table, ident);
1070 int __connman_config_init(void)
1074 config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1075 NULL, unregister_config);
1077 connman_inotify_register(STORAGEDIR, config_notify_handler);
1079 return read_configs();
1082 void __connman_config_cleanup(void)
1088 connman_inotify_unregister(STORAGEDIR, config_notify_handler);
1090 g_hash_table_destroy(config_table);
1091 config_table = NULL;
1096 char *__connman_config_get_string(GKeyFile *key_file,
1097 const char *group_name, const char *key, GError **error)
1099 char *str = g_key_file_get_string(key_file, group_name, key, error);
1103 /* passphrases can have spaces in the end */
1104 if (!g_strcmp0(key, SERVICE_KEY_PASSPHRASE) ||
1105 !g_strcmp0(key, SERVICE_KEY_PRV_KEY_PASS))
1108 return g_strchomp(str);
1111 char **__connman_config_get_string_list(GKeyFile *key_file,
1112 const char *group_name, const char *key, gsize *length, GError **error)
1115 char **strlist = g_key_file_get_string_list(key_file, group_name, key,
1122 *p = g_strstrip(*p);
1129 bool __connman_config_get_bool(GKeyFile *key_file,
1130 const char *group_name, const char *key, GError **error)
1135 valstr = g_key_file_get_value(key_file, group_name, key, error);
1139 valstr = g_strchomp(valstr);
1140 if (strcmp(valstr, "true") == 0 || strcmp(valstr, "1") == 0)
1148 static char *config_pem_fsid(const char *pem_file)
1151 unsigned *fsid = (unsigned *) &buf.f_fsid;
1152 unsigned long long fsid64;
1157 if (statfs(pem_file, &buf) < 0) {
1158 connman_error("statfs error %s for %s",
1159 strerror(errno), pem_file);
1163 fsid64 = ((unsigned long long) fsid[0] << 32) | fsid[1];
1165 return g_strdup_printf("%llx", fsid64);
1168 static void provision_service_wifi(struct connman_config_service *config,
1169 struct connman_service *service,
1170 struct connman_network *network,
1171 const void *ssid, unsigned int ssid_len)
1174 __connman_service_set_string(service, "EAP", config->eap);
1176 if (config->identity)
1177 __connman_service_set_string(service, "Identity",
1180 if (config->anonymous_identity)
1181 __connman_service_set_string(service, "AnonymousIdentity",
1182 config->anonymous_identity);
1184 if (config->ca_cert_file)
1185 __connman_service_set_string(service, "CACertFile",
1186 config->ca_cert_file);
1188 if (config->subject_match)
1189 __connman_service_set_string(service, "SubjectMatch",
1190 config->subject_match);
1192 if (config->altsubject_match)
1193 __connman_service_set_string(service, "AltSubjectMatch",
1194 config->altsubject_match);
1196 if (config->domain_suffix_match)
1197 __connman_service_set_string(service, "DomainSuffixMatch",
1198 config->domain_suffix_match);
1200 if (config->domain_match)
1201 __connman_service_set_string(service, "DomainMatch",
1202 config->domain_match);
1204 if (config->client_cert_file)
1205 __connman_service_set_string(service, "ClientCertFile",
1206 config->client_cert_file);
1208 if (config->private_key_file)
1209 __connman_service_set_string(service, "PrivateKeyFile",
1210 config->private_key_file);
1212 if (g_strcmp0(config->private_key_passphrase_type, "fsid") == 0 &&
1213 config->private_key_file) {
1216 fsid = config_pem_fsid(config->private_key_file);
1220 g_free(config->private_key_passphrase);
1221 config->private_key_passphrase = fsid;
1224 if (config->private_key_passphrase) {
1225 __connman_service_set_string(service, "PrivateKeyPassphrase",
1226 config->private_key_passphrase);
1228 * TODO: Support for PEAP with both identity and key passwd.
1229 * In that case, we should check if both of them are found
1230 * from the config file. If not, we should not set the
1231 * service passphrase in order for the UI to request for an
1232 * additional passphrase.
1237 __connman_service_set_string(service, "Phase2", config->phase2);
1238 #if defined TIZEN_EXT
1240 __connman_service_set_string(service, "Phase2", NULL);
1243 if (config->passphrase)
1244 __connman_service_set_string(service, "Passphrase",
1245 config->passphrase);
1248 __connman_service_set_hidden(service);
1250 #if defined TIZEN_EXT
1251 if (config->connector)
1252 __connman_service_set_string(service, "Connector",
1254 if (config->c_sign_key)
1255 __connman_service_set_string(service, "CSignKey",
1256 config->c_sign_key);
1257 if (config->net_access_key)
1258 __connman_service_set_string(service, "NetAccessKey",
1259 config->net_access_key);
1263 struct connect_virtual {
1264 struct connman_service *service;
1268 static gboolean remove_virtual_config(gpointer user_data)
1270 struct connect_virtual *virtual = user_data;
1272 __connman_service_connect(virtual->service,
1273 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
1274 g_hash_table_remove(config_table, virtual->vfile);
1281 #if defined TIZEN_EXT
1282 static bool __check_address_type(int address_family, const char *address)
1284 unsigned char buf[sizeof(struct in6_addr)] = {0, };
1287 err = inet_pton(address_family, address, buf);
1295 static int try_provision_service(struct connman_config_service *config,
1296 struct connman_service *service)
1298 struct connman_network *network;
1299 const void *service_id;
1300 enum connman_service_type type;
1302 unsigned int ssid_len;
1305 network = __connman_service_get_network(service);
1307 connman_error("Service has no network set");
1311 DBG("network %p ident %s", network,
1312 connman_network_get_identifier(network));
1314 type = connman_service_get_type(service);
1317 case CONNMAN_SERVICE_TYPE_WIFI:
1318 if (__connman_service_string2type(config->type) != type)
1321 ssid = connman_network_get_blob(network, "WiFi.SSID",
1326 if (!config->ssid || ssid_len != config->ssid_len)
1329 if (memcmp(config->ssid, ssid, ssid_len))
1332 str = connman_network_get_string(network, "WiFi.Security");
1333 if (config->security != __connman_service_string2security(str))
1338 case CONNMAN_SERVICE_TYPE_ETHERNET:
1339 case CONNMAN_SERVICE_TYPE_GADGET:
1341 if (__connman_service_string2type(config->type) != type)
1346 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1347 case CONNMAN_SERVICE_TYPE_SYSTEM:
1348 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1349 case CONNMAN_SERVICE_TYPE_CELLULAR:
1350 case CONNMAN_SERVICE_TYPE_GPS:
1351 case CONNMAN_SERVICE_TYPE_VPN:
1352 case CONNMAN_SERVICE_TYPE_P2P:
1353 #if defined TIZEN_EXT_WIFI_MESH
1354 case CONNMAN_SERVICE_TYPE_MESH:
1360 DBG("service %p ident %s", service,
1361 connman_service_get_identifier(service));
1364 struct connman_device *device;
1365 const char *device_addr;
1367 device = connman_network_get_device(network);
1369 connman_error("Network device is missing");
1373 device_addr = connman_device_get_string(device, "Address");
1375 DBG("wants %s has %s", config->mac, device_addr);
1377 if (g_ascii_strcasecmp(device_addr, config->mac) != 0)
1379 } else if (config->devname) {
1380 struct connman_device *device;
1381 const char *devname;
1383 device = connman_network_get_device(network);
1385 connman_error("Network device is missing");
1389 devname = connman_device_get_string(device, "Interface");
1391 DBG("wants %s has %s", config->devname, devname);
1393 if (g_ascii_strcasecmp(devname, config->devname) != 0)
1397 #if defined TIZEN_EXT
1398 struct connman_ipconfig *ip6config = __connman_service_get_ip6config(service);
1399 enum connman_ipconfig_method ipv6_method = __connman_ipconfig_get_method(ip6config);
1400 if (ipv6_method == CONNMAN_IPCONFIG_METHOD_MANUAL)
1403 if (!config->ipv6_address) {
1404 connman_network_set_ipv6_method(network,
1405 CONNMAN_IPCONFIG_METHOD_AUTO);
1406 } else if (g_ascii_strcasecmp(config->ipv6_address, "off") == 0) {
1407 connman_network_set_ipv6_method(network,
1408 CONNMAN_IPCONFIG_METHOD_OFF);
1409 } else if (g_ascii_strcasecmp(config->ipv6_address, "auto") == 0 ||
1410 g_ascii_strcasecmp(config->ipv6_address, "dhcp") == 0) {
1411 connman_network_set_ipv6_method(network,
1412 CONNMAN_IPCONFIG_METHOD_AUTO);
1414 struct connman_ipaddress *address;
1416 if (config->ipv6_prefix_length == 0) {
1417 DBG("IPv6 prefix missing");
1421 address = connman_ipaddress_alloc(AF_INET6);
1425 connman_ipaddress_set_ipv6(address, config->ipv6_address,
1426 config->ipv6_prefix_length,
1427 config->ipv6_gateway);
1429 connman_network_set_ipv6_method(network,
1430 CONNMAN_IPCONFIG_METHOD_FIXED);
1432 if (connman_network_set_ipaddress(network, address) < 0)
1433 DBG("Unable to set IPv6 address to network %p",
1436 connman_ipaddress_free(address);
1439 #if defined TIZEN_EXT
1442 if (config->ipv6_privacy) {
1443 struct connman_ipconfig *ipconfig;
1445 ipconfig = __connman_service_get_ip6config(service);
1447 __connman_ipconfig_ipv6_set_privacy(ipconfig,
1448 config->ipv6_privacy);
1451 #if defined TIZEN_EXT
1452 struct connman_ipconfig *ip4config = __connman_service_get_ip4config(service);
1453 enum connman_ipconfig_method ipv4_method = __connman_ipconfig_get_method(ip4config);
1454 if (ipv4_method == CONNMAN_IPCONFIG_METHOD_MANUAL)
1457 if (!config->ipv4_address) {
1458 connman_network_set_ipv4_method(network,
1459 CONNMAN_IPCONFIG_METHOD_DHCP);
1460 } else if (g_ascii_strcasecmp(config->ipv4_address, "off") == 0) {
1461 connman_network_set_ipv4_method(network,
1462 CONNMAN_IPCONFIG_METHOD_OFF);
1463 } else if (g_ascii_strcasecmp(config->ipv4_address, "auto") == 0 ||
1464 g_ascii_strcasecmp(config->ipv4_address, "dhcp") == 0) {
1465 connman_network_set_ipv4_method(network,
1466 CONNMAN_IPCONFIG_METHOD_DHCP);
1468 struct connman_ipaddress *address;
1470 if (!config->ipv4_netmask) {
1471 DBG("IPv4 netmask missing");
1475 address = connman_ipaddress_alloc(AF_INET);
1479 connman_ipaddress_set_ipv4(address, config->ipv4_address,
1480 config->ipv4_netmask,
1481 config->ipv4_gateway);
1483 connman_network_set_ipv4_method(network,
1484 CONNMAN_IPCONFIG_METHOD_FIXED);
1486 if (connman_network_set_ipaddress(network, address) < 0)
1487 DBG("Unable to set IPv4 address to network %p",
1490 connman_ipaddress_free(address);
1493 #if defined TIZEN_EXT
1496 __connman_service_disconnect(service);
1498 service_id = connman_service_get_identifier(service);
1499 config->service_identifiers =
1500 g_slist_prepend(config->service_identifiers,
1501 g_strdup(service_id));
1503 __connman_service_set_favorite_delayed(service, true, true);
1505 __connman_service_set_config(service, config->config_ident,
1506 config->config_entry);
1508 if (config->domain_name)
1509 __connman_service_set_domainname(service, config->domain_name);
1511 if (config->nameservers) {
1514 __connman_service_nameserver_clear(service);
1516 for (i = 0; config->nameservers[i]; i++) {
1517 #if defined TIZEN_EXT
1518 if (__check_address_type(AF_INET, config->nameservers[i]))
1519 __connman_service_nameserver_append(service,
1520 config->nameservers[i], false,
1521 CONNMAN_IPCONFIG_TYPE_IPV4);
1522 else if (__check_address_type(AF_INET6, config->nameservers[i]))
1523 __connman_service_nameserver_append(service,
1524 config->nameservers[i], false,
1525 CONNMAN_IPCONFIG_TYPE_IPV6);
1527 __connman_service_nameserver_append(service,
1528 config->nameservers[i], false);
1533 if (config->search_domains)
1534 __connman_service_set_search_domains(service,
1535 config->search_domains);
1537 __connman_service_set_mdns(service, config->mdns);
1539 if (config->timeservers)
1540 __connman_service_set_timeservers(service,
1541 config->timeservers);
1543 if (type == CONNMAN_SERVICE_TYPE_WIFI) {
1544 provision_service_wifi(config, service, network,
1548 __connman_service_mark_dirty();
1550 __connman_service_load_modifiable(service);
1552 if (config->virtual) {
1553 struct connect_virtual *virtual;
1555 virtual = g_malloc0(sizeof(struct connect_virtual));
1556 virtual->service = service;
1557 virtual->vfile = config->virtual_file;
1559 g_idle_add(remove_virtual_config, virtual);
1564 #if !defined TIZEN_EXT
1565 __connman_service_set_immutable(service, true);
1568 if (type == CONNMAN_SERVICE_TYPE_ETHERNET ||
1569 type == CONNMAN_SERVICE_TYPE_GADGET) {
1570 __connman_service_connect(service,
1571 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
1576 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
1582 find_and_provision_service_from_config(struct connman_service *service,
1583 struct connman_config *config)
1585 GHashTableIter iter;
1586 gpointer value, key;
1588 g_hash_table_iter_init(&iter, config->service_table);
1589 while (g_hash_table_iter_next(&iter, &key,
1591 if (!try_provision_service(value, service))
1598 static int find_and_provision_service(struct connman_service *service)
1600 GHashTableIter iter;
1601 gpointer value, key;
1603 g_hash_table_iter_init(&iter, config_table);
1605 while (g_hash_table_iter_next(&iter, &key, &value)) {
1606 struct connman_config *config = value;
1608 if (!find_and_provision_service_from_config(service, config))
1615 int __connman_config_provision_service(struct connman_service *service)
1617 enum connman_service_type type;
1619 /* For now only WiFi, Gadget and Ethernet services are supported */
1620 type = connman_service_get_type(service);
1621 #if defined TIZEN_EXT
1622 if (!simplified_log)
1624 DBG("service %p type %d", service, type);
1626 if (type != CONNMAN_SERVICE_TYPE_WIFI &&
1627 type != CONNMAN_SERVICE_TYPE_ETHERNET &&
1628 type != CONNMAN_SERVICE_TYPE_GADGET)
1631 #if defined TIZEN_EXT
1632 if(type == CONNMAN_SERVICE_TYPE_WIFI &&
1633 __connman_service_get_security(service) ==
1634 CONNMAN_SERVICE_SECURITY_NONE)
1638 return find_and_provision_service(service);
1641 int __connman_config_provision_service_ident(struct connman_service *service,
1642 const char *ident, const char *file, const char *entry)
1644 enum connman_service_type type;
1645 struct connman_config *config;
1648 /* For now only WiFi, Gadget and Ethernet services are supported */
1649 type = connman_service_get_type(service);
1651 DBG("service %p type %d", service, type);
1653 if (type != CONNMAN_SERVICE_TYPE_WIFI &&
1654 type != CONNMAN_SERVICE_TYPE_ETHERNET &&
1655 type != CONNMAN_SERVICE_TYPE_GADGET)
1658 config = g_hash_table_lookup(config_table, ident);
1660 GHashTableIter iter;
1661 gpointer value, key;
1664 g_hash_table_iter_init(&iter, config->service_table);
1667 * Check if we need to remove individual service if it
1668 * is missing from config file.
1670 if (file && entry) {
1671 while (g_hash_table_iter_next(&iter, &key,
1673 struct connman_config_service *config_service;
1675 config_service = value;
1677 if (g_strcmp0(config_service->config_ident,
1681 if (g_strcmp0(config_service->config_entry,
1689 DBG("found %d ident %s file %s entry %s", found, ident,
1694 * The entry+8 will skip "service_" prefix
1696 g_hash_table_remove(config->service_table,
1702 find_and_provision_service_from_config(service, config);
1708 static void generate_random_string(char *str, int length)
1714 memset(str, '\0', length);
1716 for (i = 0; i < length-1; i++) {
1718 __connman_util_get_random(&rand);
1719 val = (uint8_t)(rand % 122);
1722 } while((val > 57 && val < 65) || (val > 90 && val < 97));
1728 int connman_config_provision_mutable_service(GKeyFile *keyfile)
1730 struct connman_config_service *service_config;
1731 struct connman_config *config;
1732 char *vfile, *group = NULL;
1737 generate_random_string(rstr, 11);
1739 vfile = g_strdup_printf("service_mutable_%s.config", rstr);
1741 config = create_config(vfile);
1745 if (!load_service_from_keyfile(keyfile, config))
1748 group = g_key_file_get_start_group(keyfile);
1750 service_config = g_hash_table_lookup(config->service_table, group+8);
1751 if (!service_config)
1754 /* Specific to non file based config: */
1755 g_free(service_config->config_ident);
1756 service_config->config_ident = NULL;
1757 g_free(service_config->config_entry);
1758 service_config->config_entry = NULL;
1760 service_config->virtual = true;
1761 service_config->virtual_file = vfile;
1763 __connman_service_provision_changed(vfile);
1765 if (g_strcmp0(service_config->type, "wifi") == 0)
1766 __connman_device_request_scan(CONNMAN_SERVICE_TYPE_WIFI);
1772 DBG("Could not proceed");
1773 g_hash_table_remove(config_table, vfile);
1779 struct connman_config_entry **connman_config_get_entries(const char *type)
1781 GHashTableIter iter_file, iter_config;
1782 gpointer value, key;
1783 struct connman_config_entry **entries = NULL;
1786 g_hash_table_iter_init(&iter_file, config_table);
1787 while (g_hash_table_iter_next(&iter_file, &key, &value)) {
1788 struct connman_config *config_file = value;
1789 struct connman_config_entry **tmp_entries = entries;
1791 count = g_hash_table_size(config_file->service_table);
1793 entries = g_try_realloc(entries, (i + count + 1) *
1794 sizeof(struct connman_config_entry *));
1796 g_free(tmp_entries);
1800 g_hash_table_iter_init(&iter_config,
1801 config_file->service_table);
1802 while (g_hash_table_iter_next(&iter_config, &key,
1804 struct connman_config_service *config = value;
1807 g_strcmp0(config->type, type) != 0)
1810 entries[i] = g_try_new0(struct connman_config_entry,
1815 entries[i]->ident = g_strdup(config->ident);
1816 entries[i]->name = g_strdup(config->name);
1817 entries[i]->ssid = g_try_malloc0(config->ssid_len + 1);
1818 if (!entries[i]->ssid)
1821 memcpy(entries[i]->ssid, config->ssid,
1823 entries[i]->ssid_len = config->ssid_len;
1824 entries[i]->hidden = config->hidden;
1831 struct connman_config_entry **tmp_entries = entries;
1833 entries = g_try_realloc(entries, (i + 1) *
1834 sizeof(struct connman_config_entry *));
1836 g_free(tmp_entries);
1842 DBG("%d provisioned AP found", i);
1848 connman_config_free_entries(entries);
1852 void connman_config_free_entries(struct connman_config_entry **entries)
1859 for (i = 0; entries[i]; i++) {
1860 g_free(entries[i]->ident);
1861 g_free(entries[i]->name);
1862 g_free(entries[i]->ssid);
1869 bool __connman_config_address_provisioned(const char *address,
1870 const char *netmask)
1872 GHashTableIter iter, siter;
1873 gpointer value, key, svalue, skey;
1875 if (!address || !netmask)
1878 g_hash_table_iter_init(&iter, config_table);
1880 while (g_hash_table_iter_next(&iter, &key, &value)) {
1881 struct connman_config *config = value;
1883 g_hash_table_iter_init(&siter, config->service_table);
1884 while (g_hash_table_iter_next(&siter, &skey, &svalue)) {
1885 struct connman_config_service *service = svalue;
1887 if (!g_strcmp0(address, service->ipv4_address) &&
1889 service->ipv4_netmask))