Imported Upstream version 1.38
[platform/upstream/connman.git] / src / config.c
index 93a788a..62023b1 100644 (file)
@@ -45,7 +45,12 @@ struct connman_config_service {
        unsigned int ssid_len;
        char *eap;
        char *identity;
+       char *anonymous_identity;
        char *ca_cert_file;
+       char *subject_match;
+       char *altsubject_match;
+       char *domain_suffix_match;
+       char *domain_match;
        char *client_cert_file;
        char *private_key_file;
        char *private_key_passphrase;
@@ -67,6 +72,8 @@ struct connman_config_service {
        char *ipv6_gateway;
        char *ipv6_privacy;
        char *mac;
+       char *devname;
+       bool mdns;
        char **nameservers;
        char **search_domains;
        char **timeservers;
@@ -98,15 +105,22 @@ static bool cleanup = false;
 #define SERVICE_KEY_PRV_KEY_PASS       "PrivateKeyPassphrase"
 #define SERVICE_KEY_PRV_KEY_PASS_TYPE  "PrivateKeyPassphraseType"
 #define SERVICE_KEY_IDENTITY           "Identity"
+#define SERVICE_KEY_ANONYMOUS_IDENTITY "AnonymousIdentity"
+#define SERVICE_KEY_SUBJECT_MATCH      "SubjectMatch"
+#define SERVICE_KEY_ALT_SUBJECT_MATCH  "AltSubjectMatch"
+#define SERVICE_KEY_DOMAIN_SUFF_MATCH  "DomainSuffixMatch"
+#define SERVICE_KEY_DOMAIN_MATCH       "DomainMatch"
 #define SERVICE_KEY_PHASE2             "Phase2"
 #define SERVICE_KEY_PASSPHRASE         "Passphrase"
 #define SERVICE_KEY_SECURITY           "Security"
 #define SERVICE_KEY_HIDDEN             "Hidden"
+#define SERVICE_KEY_MDNS               "mDNS"
 
 #define SERVICE_KEY_IPv4               "IPv4"
 #define SERVICE_KEY_IPv6               "IPv6"
 #define SERVICE_KEY_IPv6_PRIVACY       "IPv6.Privacy"
 #define SERVICE_KEY_MAC                "MAC"
+#define SERVICE_KEY_DEVICE_NAME               "DeviceName"
 #define SERVICE_KEY_NAMESERVERS        "Nameservers"
 #define SERVICE_KEY_SEARCH_DOMAINS     "SearchDomains"
 #define SERVICE_KEY_TIMESERVERS        "Timeservers"
@@ -129,6 +143,11 @@ static const char *service_possible_keys[] = {
        SERVICE_KEY_PRV_KEY_PASS,
        SERVICE_KEY_PRV_KEY_PASS_TYPE,
        SERVICE_KEY_IDENTITY,
+       SERVICE_KEY_ANONYMOUS_IDENTITY,
+       SERVICE_KEY_SUBJECT_MATCH,
+       SERVICE_KEY_ALT_SUBJECT_MATCH,
+       SERVICE_KEY_DOMAIN_SUFF_MATCH,
+       SERVICE_KEY_DOMAIN_MATCH,
        SERVICE_KEY_PHASE2,
        SERVICE_KEY_PASSPHRASE,
        SERVICE_KEY_SECURITY,
@@ -137,6 +156,8 @@ static const char *service_possible_keys[] = {
        SERVICE_KEY_IPv6,
        SERVICE_KEY_IPv6_PRIVACY,
        SERVICE_KEY_MAC,
+       SERVICE_KEY_DEVICE_NAME,
+       SERVICE_KEY_MDNS,
        SERVICE_KEY_NAMESERVERS,
        SERVICE_KEY_SEARCH_DOMAINS,
        SERVICE_KEY_TIMESERVERS,
@@ -178,7 +199,7 @@ static void unregister_service(gpointer data)
                                                        list = list->next) {
                service_id = list->data;
 
-               service = __connman_service_lookup_from_ident(service_id);
+               service = connman_service_lookup_from_identifier(service_id);
                if (service) {
                        __connman_service_set_immutable(service, false);
                        __connman_service_set_config(service, NULL, NULL);
@@ -220,7 +241,12 @@ free_only:
        g_free(config_service->ssid);
        g_free(config_service->eap);
        g_free(config_service->identity);
+       g_free(config_service->anonymous_identity);
        g_free(config_service->ca_cert_file);
+       g_free(config_service->subject_match);
+       g_free(config_service->altsubject_match);
+       g_free(config_service->domain_suffix_match);
+       g_free(config_service->domain_match);
        g_free(config_service->client_cert_file);
        g_free(config_service->private_key_file);
        g_free(config_service->private_key_passphrase);
@@ -234,6 +260,7 @@ free_only:
        g_free(config_service->ipv6_gateway);
        g_free(config_service->ipv6_privacy);
        g_free(config_service->mac);
+       g_free(config_service->devname);
        g_strfreev(config_service->nameservers);
        g_strfreev(config_service->search_domains);
        g_strfreev(config_service->timeservers);
@@ -455,6 +482,12 @@ static bool load_service_generic(GKeyFile *keyfile,
                service->mac = str;
        }
 
+       str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DEVICE_NAME, NULL);
+       if (str) {
+               g_free(service->devname);
+               service->devname = str;
+       }
+
        str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DOMAIN, NULL);
        if (str) {
                g_free(service->domain_name);
@@ -494,6 +527,9 @@ static bool load_service_generic(GKeyFile *keyfile,
                        g_strfreev(strlist);
        }
 
+       service->mdns = __connman_config_get_bool(keyfile, group,
+                                               SERVICE_KEY_MDNS, NULL);
+
        return true;
 
 err:
@@ -505,6 +541,7 @@ err:
        g_free(service->ipv6_address);
        g_free(service->ipv6_gateway);
        g_free(service->mac);
+       g_free(service->devname);
        g_free(service);
 
        return false;
@@ -544,8 +581,8 @@ static bool load_service(GKeyFile *keyfile, const char *group,
                g_free(service->type);
                service->type = str;
        } else {
-               DBG("Type of the configured service is missing for group %s",
-                                                                       group);
+               connman_warn("Type of the configured service is missing "
+                       "for group %s", group);
                goto err;
        }
 
@@ -655,6 +692,41 @@ static bool load_service(GKeyFile *keyfile, const char *group,
                service->identity = str;
        }
 
+       str = __connman_config_get_string(keyfile, group,
+                                       SERVICE_KEY_ANONYMOUS_IDENTITY, NULL);
+       if (str) {
+               g_free(service->anonymous_identity);
+               service->anonymous_identity = str;
+       }
+
+       str = __connman_config_get_string(keyfile, group,
+                                       SERVICE_KEY_SUBJECT_MATCH, NULL);
+       if (str) {
+               g_free(service->subject_match);
+               service->subject_match = str;
+       }
+
+       str = __connman_config_get_string(keyfile, group,
+                                       SERVICE_KEY_ALT_SUBJECT_MATCH, NULL);
+       if (str) {
+               g_free(service->altsubject_match);
+               service->altsubject_match = str;
+       }
+
+       str = __connman_config_get_string(keyfile, group,
+                                       SERVICE_KEY_DOMAIN_SUFF_MATCH, NULL);
+       if (str) {
+               g_free(service->domain_suffix_match);
+               service->domain_suffix_match = str;
+       }
+
+       str = __connman_config_get_string(keyfile, group,
+                                       SERVICE_KEY_DOMAIN_MATCH, NULL);
+       if (str) {
+               g_free(service->domain_match);
+               service->domain_match = str;
+       }
+
        str = __connman_config_get_string(keyfile, group, SERVICE_KEY_PHASE2, NULL);
        if (str) {
                g_free(service->phase2);
@@ -698,7 +770,18 @@ static bool load_service(GKeyFile *keyfile, const char *group,
 
                } else
                        service->security = CONNMAN_SERVICE_SECURITY_PSK;
-       }
+       } else if (str) {
+
+               if (security != CONNMAN_SERVICE_SECURITY_NONE)
+                       connman_info("Mismatch no security and "
+                                       "setting %s = %s",
+                                       SERVICE_KEY_SECURITY, str);
+
+               service->security = CONNMAN_SERVICE_SECURITY_NONE;
+       } else
+               service->security = CONNMAN_SERVICE_SECURITY_NONE;
+
+       g_free(str);
 
        service->config_ident = g_strdup(config->ident);
        service->config_entry = g_strdup_printf("service_%s", service->ident);
@@ -736,8 +819,11 @@ static bool load_service_from_keyfile(GKeyFile *keyfile,
        groups = g_key_file_get_groups(keyfile, NULL);
 
        for (i = 0; groups[i]; i++) {
-               if (!g_str_has_prefix(groups[i], "service_"))
+               if (!g_str_has_prefix(groups[i], "service_")) {
+                       connman_warn("Ignore group named '%s' because prefix "
+                               "is not 'service_'", groups[i]);
                        continue;
+               }
                if (load_service(keyfile, groups[i], config))
                        found = true;
        }
@@ -891,10 +977,10 @@ static void config_notify_handler(struct inotify_event *event,
                return;
        }
 
-       if (event->mask & IN_CREATE)
+       if (event->mask & (IN_CREATE | IN_MOVED_TO))
                create_config(ident);
 
-       if (event->mask & IN_MODIFY) {
+       if (event->mask & (IN_MODIFY | IN_MOVED_TO)) {
                struct connman_config *config;
 
                config = g_hash_table_lookup(config_table, ident);
@@ -916,7 +1002,7 @@ static void config_notify_handler(struct inotify_event *event,
                }
        }
 
-       if (event->mask & IN_DELETE)
+       if (event->mask & (IN_DELETE | IN_MOVED_FROM))
                g_hash_table_remove(config_table, ident);
 }
 
@@ -953,6 +1039,11 @@ char *__connman_config_get_string(GKeyFile *key_file,
        if (!str)
                return NULL;
 
+       /* passphrases can have spaces in the end */
+       if (!g_strcmp0(key, SERVICE_KEY_PASSPHRASE) ||
+                       !g_strcmp0(key, SERVICE_KEY_PRV_KEY_PASS))
+               return str;
+
        return g_strchomp(str);
 }
 
@@ -1025,10 +1116,30 @@ static void provision_service_wifi(struct connman_config_service *config,
                __connman_service_set_string(service, "Identity",
                                                        config->identity);
 
+       if (config->anonymous_identity)
+               __connman_service_set_string(service, "AnonymousIdentity",
+                                               config->anonymous_identity);
+
        if (config->ca_cert_file)
                __connman_service_set_string(service, "CACertFile",
                                                        config->ca_cert_file);
 
+       if (config->subject_match)
+               __connman_service_set_string(service, "SubjectMatch",
+                                                       config->subject_match);
+
+       if (config->altsubject_match)
+               __connman_service_set_string(service, "AltSubjectMatch",
+                                                       config->altsubject_match);
+
+       if (config->domain_suffix_match)
+               __connman_service_set_string(service, "DomainSuffixMatch",
+                                                       config->domain_suffix_match);
+
+       if (config->domain_match)
+               __connman_service_set_string(service, "DomainMatch",
+                                                       config->domain_match);
+
        if (config->client_cert_file)
                __connman_service_set_string(service, "ClientCertFile",
                                                config->client_cert_file);
@@ -1118,10 +1229,8 @@ static int try_provision_service(struct connman_config_service *config,
 
                ssid = connman_network_get_blob(network, "WiFi.SSID",
                                                &ssid_len);
-               if (!ssid) {
-                       connman_error("Network SSID not set");
-                       return -EINVAL;
-               }
+               if (!ssid)
+                       return -ENOENT;
 
                if (!config->ssid || ssid_len != config->ssid_len)
                        return -ENOENT;
@@ -1155,7 +1264,7 @@ static int try_provision_service(struct connman_config_service *config,
        }
 
        DBG("service %p ident %s", service,
-                                       __connman_service_get_ident(service));
+                               connman_service_get_identifier(service));
 
        if (config->mac) {
                struct connman_device *device;
@@ -1173,6 +1282,22 @@ static int try_provision_service(struct connman_config_service *config,
 
                if (g_ascii_strcasecmp(device_addr, config->mac) != 0)
                        return -ENOENT;
+       } else if (config->devname) {
+               struct connman_device *device;
+               const char *devname;
+
+               device = connman_network_get_device(network);
+               if (!device) {
+                       connman_error("Network device is missing");
+                       return -ENODEV;
+               }
+
+               devname = connman_device_get_string(device, "Interface");
+
+               DBG("wants %s has %s", config->devname, devname);
+
+               if (g_ascii_strcasecmp(devname, config->devname) != 0)
+                       return -ENOENT;
        }
 
        if (!config->ipv6_address) {
@@ -1258,7 +1383,7 @@ static int try_provision_service(struct connman_config_service *config,
 
        __connman_service_disconnect(service);
 
-       service_id = __connman_service_get_ident(service);
+       service_id = connman_service_get_identifier(service);
        config->service_identifiers =
                g_slist_prepend(config->service_identifiers,
                                g_strdup(service_id));
@@ -1286,6 +1411,8 @@ static int try_provision_service(struct connman_config_service *config,
                __connman_service_set_search_domains(service,
                                                config->search_domains);
 
+       __connman_service_set_mdns(service, config->mdns);
+
        if (config->timeservers)
                __connman_service_set_timeservers(service,
                                                config->timeservers);
@@ -1306,7 +1433,7 @@ static int try_provision_service(struct connman_config_service *config,
                virtual->service = service;
                virtual->vfile = config->virtual_file;
 
-               g_timeout_add(0, remove_virtual_config, virtual);
+               g_idle_add(remove_virtual_config, virtual);
 
                return 0;
        }
@@ -1326,22 +1453,35 @@ static int try_provision_service(struct connman_config_service *config,
        return 0;
 }
 
+static int
+find_and_provision_service_from_config(struct connman_service *service,
+                                       struct connman_config *config)
+{
+       GHashTableIter iter;
+       gpointer value, key;
+
+       g_hash_table_iter_init(&iter, config->service_table);
+       while (g_hash_table_iter_next(&iter, &key,
+                                       &value)) {
+               if (!try_provision_service(value, service))
+                       return 0;
+       }
+
+       return -ENOENT;
+}
+
 static int find_and_provision_service(struct connman_service *service)
 {
-       GHashTableIter iter, iter_service;
-       gpointer value, key, value_service, key_service;
+       GHashTableIter iter;
+       gpointer value, key;
 
        g_hash_table_iter_init(&iter, config_table);
 
        while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct connman_config *config = value;
 
-               g_hash_table_iter_init(&iter_service, config->service_table);
-               while (g_hash_table_iter_next(&iter_service, &key_service,
-                                               &value_service)) {
-                       if (!try_provision_service(value_service, service))
-                               return 0;
-               }
+               if (!find_and_provision_service_from_config(service, config))
+                       return 0;
        }
 
        return -ENOENT;
@@ -1425,7 +1565,7 @@ int __connman_config_provision_service_ident(struct connman_service *service,
                        }
                }
 
-               find_and_provision_service(service);
+               find_and_provision_service_from_config(service, config);
        }
 
        return ret;
@@ -1435,12 +1575,14 @@ static void generate_random_string(char *str, int length)
 {
        uint8_t val;
        int i;
+       uint64_t rand;
 
        memset(str, '\0', length);
 
        for (i = 0; i < length-1; i++) {
                do {
-                       val = (uint8_t)(random() % 122);
+                       __connman_util_get_random(&rand);
+                       val = (uint8_t)(rand % 122);
                        if (val < 48)
                                val += 48;
                } while((val > 57 && val < 65) || (val > 90 && val < 97));
@@ -1453,7 +1595,7 @@ int connman_config_provision_mutable_service(GKeyFile *keyfile)
 {
        struct connman_config_service *service_config;
        struct connman_config *config;
-       char *vfile, *group;
+       char *vfile, *group = NULL;
        char rstr[11];
 
        DBG("");
@@ -1489,13 +1631,14 @@ int connman_config_provision_mutable_service(GKeyFile *keyfile)
        if (g_strcmp0(service_config->type, "wifi") == 0)
                __connman_device_request_scan(CONNMAN_SERVICE_TYPE_WIFI);
 
+       g_free(group);
        return 0;
 
 error:
        DBG("Could not proceed");
        g_hash_table_remove(config_table, vfile);
        g_free(vfile);
-
+       g_free(group);
        return -EINVAL;
 }
 
@@ -1509,13 +1652,16 @@ struct connman_config_entry **connman_config_get_entries(const char *type)
        g_hash_table_iter_init(&iter_file, config_table);
        while (g_hash_table_iter_next(&iter_file, &key, &value)) {
                struct connman_config *config_file = value;
+               struct connman_config_entry **tmp_entries = entries;
 
                count = g_hash_table_size(config_file->service_table);
 
                entries = g_try_realloc(entries, (i + count + 1) *
                                        sizeof(struct connman_config_entry *));
-               if (!entries)
+               if (!entries) {
+                       g_free(tmp_entries);
                        return NULL;
+               }
 
                g_hash_table_iter_init(&iter_config,
                                                config_file->service_table);
@@ -1548,10 +1694,14 @@ struct connman_config_entry **connman_config_get_entries(const char *type)
        }
 
        if (entries) {
+               struct connman_config_entry **tmp_entries = entries;
+
                entries = g_try_realloc(entries, (i + 1) *
                                        sizeof(struct connman_config_entry *));
-               if (!entries)
+               if (!entries) {
+                       g_free(tmp_entries);
                        return NULL;
+               }
 
                entries[i] = NULL;
 
@@ -1580,7 +1730,6 @@ void connman_config_free_entries(struct connman_config_entry **entries)
        }
 
        g_free(entries);
-       return;
 }
 
 bool __connman_config_address_provisioned(const char *address,