+static void unregister_config(gpointer data)
+{
+ struct connman_config *config = data;
+
+ connman_info("Removing configuration %s", config->ident);
+
+ g_hash_table_destroy(config->service_table);
+
+ g_free(config->description);
+ g_free(config->name);
+ g_free(config->ident);
+ g_free(config);
+}
+
+static void unregister_service(gpointer data)
+{
+ struct connman_config_service *service = data;
+
+ connman_info("Removing service configuration %s", service->ident);
+
+ protected_services = g_slist_remove(protected_services, service);
+
+ g_free(service->ident);
+ g_free(service->type);
+ g_free(service->name);
+ g_free(service->ssid);
+ g_free(service->eap);
+ g_free(service->identity);
+ g_free(service->ca_cert_file);
+ g_free(service->client_cert_file);
+ g_free(service->private_key_file);
+ g_free(service->private_key_passphrase);
+ g_free(service->private_key_passphrase_type);
+ g_free(service->phase2);
+ g_free(service->passphrase);
+ g_free(service);
+}
+
+static void check_keys(GKeyFile *keyfile, const char *group,
+ const char **possible_keys)
+{
+ char **avail_keys;
+ gsize nb_avail_keys, i, j;
+
+ avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
+ if (avail_keys == NULL)
+ return;
+
+ /*
+ * For each key in the configuration file,
+ * verify it is understood by connman
+ */
+ for (i = 0 ; i < nb_avail_keys; i++) {
+ for (j = 0; possible_keys[j] ; j++)
+ if (g_strcmp0(avail_keys[i], possible_keys[j]) == 0)
+ break;
+
+ if (possible_keys[j] == NULL)
+ connman_warn("Unknown configuration key %s in [%s]",
+ avail_keys[i], group);
+ }
+
+ g_strfreev(avail_keys);
+}
+
+static connman_bool_t
+is_protected_service(struct connman_config_service *service)
+{
+ GSList *list;
+
+ DBG("ident %s", service->ident);
+
+ for (list = protected_services; list; list = list->next) {
+ struct connman_config_service *s = list->data;
+
+ if (g_strcmp0(s->type, service->type) != 0)
+ continue;
+
+ if (s->ssid == NULL || service->ssid == NULL)
+ continue;
+
+ if (s->ssid_len != service->ssid_len)
+ continue;
+
+ if (g_strcmp0(service->type, "wifi") == 0 &&
+ strncmp(s->ssid, service->ssid, s->ssid_len) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int load_service(GKeyFile *keyfile, const char *group,
+ struct connman_config *config)
+{
+ struct connman_config_service *service;
+ const char *ident;
+ char *str, *hex_ssid;
+ gboolean service_created = FALSE;
+ int err;
+
+ /* Strip off "service_" prefix */
+ ident = group + 8;
+
+ if (strlen(ident) < 1)
+ return -EINVAL;
+
+ /* Verify that provided keys are good */
+ check_keys(keyfile, group, service_possible_keys);
+
+ service = g_hash_table_lookup(config->service_table, ident);
+ if (service == NULL) {
+ service = g_try_new0(struct connman_config_service, 1);
+ if (service == NULL)
+ return -ENOMEM;
+
+ service->ident = g_strdup(ident);
+
+ service_created = TRUE;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_TYPE, NULL);
+ if (str != NULL) {
+ g_free(service->type);
+ service->type = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_NAME, NULL);
+ if (str != NULL) {
+ g_free(service->name);
+ service->name = str;
+ }
+
+ hex_ssid = g_key_file_get_string(keyfile, group, SERVICE_KEY_SSID,
+ NULL);
+ if (hex_ssid != NULL) {
+ char *ssid;
+ unsigned int i, j = 0, hex;
+ size_t hex_ssid_len = strlen(hex_ssid);
+
+ ssid = g_try_malloc0(hex_ssid_len / 2);
+ if (ssid == NULL) {
+ err = -ENOMEM;
+ g_free(hex_ssid);
+ goto err;
+ }
+
+ for (i = 0; i < hex_ssid_len; i += 2) {
+ sscanf(hex_ssid + i, "%02x", &hex);
+ ssid[j++] = hex;
+ }
+
+ g_free(hex_ssid);
+
+ g_free(service->ssid);
+ service->ssid = ssid;
+ service->ssid_len = hex_ssid_len / 2;
+ } else if (service->name != NULL) {
+ char *ssid;
+ unsigned int ssid_len;
+
+ ssid_len = strlen(service->name);
+ ssid = g_try_malloc0(ssid_len);
+ if (ssid == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(ssid, service->name, ssid_len);
+ g_free(service->ssid);
+ service->ssid = ssid;
+ service->ssid_len = ssid_len;
+ }
+
+ if (is_protected_service(service) == TRUE) {
+ connman_error("Trying to provision a protected service");
+ err = -EACCES;
+ goto err;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_EAP, NULL);
+ if (str != NULL) {
+ g_free(service->eap);
+ service->eap = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_CA_CERT, NULL);
+ if (str != NULL) {
+ g_free(service->ca_cert_file);
+ service->ca_cert_file = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_CL_CERT, NULL);
+ if (str != NULL) {
+ g_free(service->client_cert_file);
+ service->client_cert_file = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PRV_KEY, NULL);
+ if (str != NULL) {
+ g_free(service->private_key_file);
+ service->private_key_file = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group,
+ SERVICE_KEY_PRV_KEY_PASS, NULL);
+ if (str != NULL) {
+ g_free(service->private_key_passphrase);
+ service->private_key_passphrase = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group,
+ SERVICE_KEY_PRV_KEY_PASS_TYPE, NULL);
+ if (str != NULL) {
+ g_free(service->private_key_passphrase_type);
+ service->private_key_passphrase_type = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_IDENTITY, NULL);
+ if (str != NULL) {
+ g_free(service->identity);
+ service->identity = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PHASE2, NULL);
+ if (str != NULL) {
+ g_free(service->phase2);
+ service->phase2 = str;
+ }
+
+ str = g_key_file_get_string(keyfile, group, SERVICE_KEY_PASSPHRASE,
+ NULL);
+ if (str != NULL) {
+ g_free(service->passphrase);
+ service->passphrase = str;
+ }
+
+ if (service_created)
+ g_hash_table_insert(config->service_table, service->ident,
+ service);
+
+ if (config->protected == TRUE)
+ protected_services =
+ g_slist_append(protected_services, service);
+
+ connman_info("Adding service configuration %s", service->ident);
+
+ return 0;
+
+err:
+ if (service_created == TRUE) {
+ g_free(service->ident);
+ g_free(service->type);
+ g_free(service->name);
+ g_free(service->ssid);
+ g_free(service);
+ }
+
+ return err;
+}