service: Check that the supplied nameserver is in numeric format
[framework/connectivity/connman.git] / src / service.c
index c9ee004..94ef7b6 100644 (file)
@@ -44,6 +44,7 @@ static GHashTable *service_hash = NULL;
 static GSList *counter_list = NULL;
 static unsigned int autoconnect_timeout = 0;
 static struct connman_service *current_default = NULL;
+static connman_bool_t services_dirty = FALSE;
 
 struct connman_stats {
        connman_bool_t valid;
@@ -678,6 +679,15 @@ static int service_save(struct connman_service *service)
                g_key_file_set_boolean(keyfile, service->identifier, "Hidden",
                                                                        TRUE);
 
+       if (service->config_file != NULL && strlen(service->config_file) > 0)
+               g_key_file_set_string(keyfile, service->identifier,
+                               "Config.file", service->config_file);
+
+       if (service->config_entry != NULL &&
+                                       strlen(service->config_entry) > 0)
+               g_key_file_set_string(keyfile, service->identifier,
+                               "Config.ident", service->config_entry);
+
 done:
        __connman_storage_save_service(keyfile, service->identifier);
 
@@ -686,6 +696,11 @@ done:
        return err;
 }
 
+void __connman_service_save(struct connman_service *service)
+{
+       service_save(service);
+}
+
 static enum connman_service_state combine_state(
                                        enum connman_service_state state_a,
                                        enum connman_service_state state_b)
@@ -3026,10 +3041,12 @@ static DBusMessage *set_property(DBusConnection *conn,
                        const char *val;
                        dbus_message_iter_get_basic(&entry, &val);
                        dbus_message_iter_next(&entry);
-                       if (str->len > 0)
-                               g_string_append_printf(str, " %s", val);
-                       else
-                               g_string_append(str, val);
+                       if (connman_inet_check_ipaddress(val) > 0) {
+                               if (str->len > 0)
+                                       g_string_append_printf(str, " %s", val);
+                               else
+                                       g_string_append(str, val);
+                       }
                }
 
                remove_nameservers(service, NULL, service->nameservers_config);
@@ -4366,15 +4383,22 @@ connman_bool_t __connman_service_wps_enabled(struct connman_service *service)
        return service->wps;
 }
 
+void __connman_service_mark_dirty()
+ {
+       services_dirty = TRUE;
+ }
+
 /**
- * __connman_service_set_favorite:
+ * __connman_service_set_favorite_delayed:
  * @service: service structure
  * @favorite: favorite value
+ * @delay_ordering: do not order service sequence
  *
  * Change the favorite setting of service
  */
-int __connman_service_set_favorite(struct connman_service *service,
-                                               connman_bool_t favorite)
+int __connman_service_set_favorite_delayed(struct connman_service *service,
+                                       connman_bool_t favorite,
+                                       gboolean delay_ordering)
 {
        GSequenceIter *iter;
 
@@ -4388,20 +4412,39 @@ int __connman_service_set_favorite(struct connman_service *service,
                return -EALREADY;
 
        service->favorite = favorite;
-       service->order = __connman_service_get_order(service);
+
+       if (delay_ordering == FALSE)
+               service->order = __connman_service_get_order(service);
 
        favorite_changed(service);
 
-       if (g_sequence_get_length(service_list) > 1) {
-               g_sequence_sort_changed(iter, service_compare, NULL);
-               service_schedule_changed();
-       }
+       if (delay_ordering == FALSE) {
 
-       __connman_connection_update_gateway();
+               if (g_sequence_get_length(service_list) > 1) {
+                       g_sequence_sort_changed(iter, service_compare, NULL);
+                       service_schedule_changed();
+               }
+
+               __connman_connection_update_gateway();
+       }
 
        return 0;
 }
 
+/**
+ * __connman_service_set_favorite:
+ * @service: service structure
+ * @favorite: favorite value
+ *
+ * Change the favorite setting of service
+ */
+int __connman_service_set_favorite(struct connman_service *service,
+                                               connman_bool_t favorite)
+{
+       return __connman_service_set_favorite_delayed(service, favorite,
+                                                       FALSE);
+}
+
 int __connman_service_set_immutable(struct connman_service *service,
                                                connman_bool_t immutable)
 {
@@ -5459,17 +5502,49 @@ static struct connman_service *lookup_by_identifier(const char *identifier)
        return NULL;
 }
 
+struct provision_user_data {
+       const char *ident;
+       int ret;
+};
+
 static void provision_changed(gpointer value, gpointer user_data)
 {
        struct connman_service *service = value;
-       char *path = user_data;
+       struct provision_user_data *data = user_data;
+       const char *path = data->ident;
+       int ret;
 
-       __connman_config_provision_service_ident(service, path);
+       ret = __connman_config_provision_service_ident(service, path,
+                       service->config_file, service->config_entry);
+       if (ret > 0)
+               data->ret = ret;
 }
 
-void __connman_service_provision_changed(const char *ident)
+int __connman_service_provision_changed(const char *ident)
 {
-       g_sequence_foreach(service_list, provision_changed, (void *)ident);
+       struct provision_user_data data = {
+               .ident = ident,
+               .ret = 0
+       };
+
+       g_sequence_foreach(service_list, provision_changed, (void *)&data);
+
+       /*
+        * Because the provision_changed() might have set some services
+        * as favorite, we must sort the sequence now.
+        */
+       if (services_dirty == TRUE) {
+               services_dirty = FALSE;
+
+               if (g_sequence_get_length(service_list) > 1) {
+                       g_sequence_sort(service_list, service_compare, NULL);
+                       service_schedule_changed();
+               }
+
+               __connman_connection_update_gateway();
+       }
+
+       return data.ret;
 }
 
 void __connman_service_set_config(struct connman_service *service,
@@ -6205,6 +6280,66 @@ __connman_service_create_from_provider(struct connman_provider *provider)
        return service;
 }
 
+static void remove_unprovisioned_services()
+{
+       gchar **services;
+       GKeyFile *keyfile, *configkeyfile;
+       char *file, *section;
+       int i = 0;
+
+       services = connman_storage_get_services();
+       if (services == NULL)
+               return;
+
+       for (;services[i] != NULL; i++) {
+               file = section = NULL;
+               keyfile = configkeyfile = NULL;
+
+               keyfile = connman_storage_load_service(services[i]);
+               if (keyfile == NULL)
+                       continue;
+
+               file = g_key_file_get_string(keyfile, services[i],
+                                       "Config.file", NULL);
+               if (file == NULL)
+                       goto next;
+
+               section = g_key_file_get_string(keyfile, services[i],
+                                       "Config.ident", NULL);
+               if (section == NULL)
+                       goto next;
+
+               configkeyfile = __connman_storage_load_config(file);
+               if (configkeyfile == NULL) {
+                       /*
+                        * Config file is missing, remove the provisioned
+                        * service.
+                        */
+                       __connman_storage_remove_service(services[i]);
+                       goto next;
+               }
+
+               if (g_key_file_has_group(configkeyfile, section) == FALSE)
+                       /*
+                        * Config section is missing, remove the provisioned
+                        * service.
+                        */
+                       __connman_storage_remove_service(services[i]);
+
+       next:
+               if (keyfile != NULL)
+                       g_key_file_free(keyfile);
+
+               if (configkeyfile != NULL)
+                       g_key_file_free(configkeyfile);
+
+               g_free(section);
+               g_free(file);
+       }
+
+       g_strfreev(services);
+}
+
 int __connman_service_init(void)
 {
        DBG("");
@@ -6221,6 +6356,8 @@ int __connman_service_init(void)
                        g_str_equal, g_free, NULL);
        services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
 
+       remove_unprovisioned_services();
+
        return 0;
 }