Load service entries from configuration files
authorSamuel Ortiz <sameo@linux.intel.com>
Wed, 23 Dec 2009 22:16:41 +0000 (23:16 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 23 Dec 2009 22:30:57 +0000 (14:30 -0800)
For IEEE 802.1x networks, the various certificate paths, private key
paths and identities are configured through an external configuration
file. They belong to a "service" group in this file and loaded at
startup.

Any matching service with the corresponding service group will be
provisioned with this configuration. These settings will also be
then propagated to the network structure at connection time.

src/config.c
src/connman.h
src/service.c

index cf8e42a..d5cfd9e 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdio.h>
+#include <string.h>
 #include <glib.h>
 
 #include "connman.h"
 
+struct connman_config_service {
+       char *type;
+       void *ssid;
+       unsigned int ssid_len;
+       char *eap;
+       char *identity;
+       char *ca_cert_file;
+       char *client_cert_file;
+       char *private_key_file;
+       char *private_key_passphrase;
+       char *phase2;
+};
+
 struct connman_config {
        char *ident;
        char *name;
        char *description;
+       struct connman_config_service *service;
 };
 
 static GHashTable *config_hash = NULL;
 
+static int load_service(GKeyFile *keyfile, struct connman_config *config)
+{
+       char *str, *hex_ssid;
+       struct connman_config_service *service;
+
+       service = g_try_new0(struct connman_config_service, 1);
+       if (service == NULL)
+               return -ENOMEM;
+
+       config->service = service;
+
+       str = g_key_file_get_string(keyfile, "service", "Type", NULL);
+       if (str != NULL) {
+               g_free(service->ssid);
+               service->type = str;
+       }
+
+       hex_ssid = g_key_file_get_string(keyfile, "service", "Type", 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) {
+                       g_free(hex_ssid);
+                       return -ENOMEM;
+               }
+
+               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->type);
+               service->ssid = ssid;
+               service->ssid_len = hex_ssid_len / 2;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "EAP", NULL);
+       if (str != NULL) {
+               g_free(service->eap);
+               service->eap = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "CACertFile", NULL);
+       if (str != NULL) {
+               g_free(service->ca_cert_file);
+               service->ca_cert_file = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "ClientCertFile", NULL);
+       if (str != NULL) {
+               g_free(service->client_cert_file);
+               service->client_cert_file = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "PrivateKeyFile", NULL);
+       if (str != NULL) {
+               g_free(service->private_key_file);
+               service->private_key_file = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "PrivateKeyPassphrase",
+                                   NULL);
+       if (str != NULL) {
+               g_free(service->private_key_passphrase);
+               service->private_key_passphrase = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "Identity", NULL);
+       if (str != NULL) {
+               g_free(service->identity);
+               service->identity = str;
+       }
+
+       str = g_key_file_get_string(keyfile, "service", "Phase2", NULL);
+       if (str != NULL) {
+               g_free(service->phase2);
+               service->phase2 = str;
+       }
+
+
+       return 0;
+}
+
+static void free_service(struct connman_config_service *service)
+{
+       g_free(service->type);
+       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->phase2);
+       g_free(service);
+}
+
 static int load_config(struct connman_config *config)
 {
        GKeyFile *keyfile;
        char *str;
+       int err;
 
        DBG("config %p", config);
 
@@ -58,9 +177,18 @@ static int load_config(struct connman_config *config)
                config->description = str;
        }
 
+       if (g_key_file_has_group(keyfile, "service") == TRUE) {
+               err = load_service(keyfile, config);
+               if (err < 0)
+                       goto done;
+       }
+
+       err = 0;
+
+done:
        __connman_storage_close_config(config->ident, keyfile, FALSE);
 
-       return 0;
+       return err;
 }
 
 static void free_config(struct connman_config *config)
@@ -68,6 +196,7 @@ static void free_config(struct connman_config *config)
        g_free(config->description);
        g_free(config->name);
        g_free(config->ident);
+       free_service(config->service);
        g_free(config);
 }
 
@@ -149,6 +278,39 @@ static int config_init(void)
        return 0;
 }
 
+static void config_service_setup(struct connman_service *service,
+                                struct connman_config_service *config)
+{
+       if (config == NULL)
+               return;
+
+       if (config->eap)
+               __connman_service_set_string(service, "EAP", config->eap);
+
+       if (config->identity)
+               __connman_service_set_string(service, "Identity",
+                                            config->identity);
+
+       if (config->ca_cert_file)
+               __connman_service_set_string(service, "CACertFile",
+                                            config->ca_cert_file);
+
+       if (config->client_cert_file)
+               __connman_service_set_string(service, "ClientCertFile",
+                                            config->client_cert_file);
+
+       if (config->private_key_file)
+               __connman_service_set_string(service, "PrivateKeyFile",
+                                            config->private_key_file);
+
+       if (config->private_key_passphrase)
+               __connman_service_set_string(service, "PrivateKeyPassphrase",
+                                            config->private_key_passphrase);
+
+       if (config->phase2)
+               __connman_service_set_string(service, "Phase2", config->phase2);
+}
+
 int __connman_config_init(void)
 {
        DBG("");
@@ -169,7 +331,42 @@ void __connman_config_cleanup(void)
 
 int __connman_config_provision_service(struct connman_service *service)
 {
+       GHashTableIter iter;
+       gpointer value, key;
+       struct connman_network *network;
+       struct connman_config *config = NULL;
+       const void *ssid;
+       unsigned int ssid_len;
+
        DBG("service %p", service);
 
+       network = __connman_service_get_network(service);
+       if (network == NULL) {
+               connman_error("Network not set");
+               return -EINVAL;
+       }
+
+       ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
+       if (ssid == NULL) {
+               connman_error("Network SSID not set");
+               return -EINVAL;
+       }
+
+       g_hash_table_iter_init(&iter, config_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+               config = value;
+
+               /* For now we only support wifi services entries */
+               if (config->service &&
+                               g_strcmp0(config->service->type, "wifi") == 0 &&
+                               ssid_len == config->service->ssid_len)
+                       if (config->service->ssid &&
+                                       memcmp(config->service->ssid, ssid,
+                                              ssid_len) == 0)
+                               break;
+       }
+
+       config_service_setup(service, config->service);
+
        return 0;
 }
index 6a36331..e7869f9 100644 (file)
@@ -375,7 +375,10 @@ void __connman_service_remove_from_network(struct connman_network *network);
 
 const char *__connman_service_get_path(struct connman_service *service);
 unsigned int __connman_service_get_order(struct connman_service *service);
+struct connman_network *__connman_service_get_network(struct connman_service *service);
 
+void __connman_service_set_string(struct connman_service *service,
+                                 const char *key, const char *value);
 int __connman_service_indicate_state(struct connman_service *service,
                                        enum connman_service_state state);
 int __connman_service_indicate_error(struct connman_service *service,
index 3092f67..167cef4 100644 (file)
@@ -65,6 +65,14 @@ struct connman_service {
        connman_bool_t roaming;
        struct connman_ipconfig *ipconfig;
        struct connman_network *network;
+       /* 802.1x settings from the config files */
+       char *eap;
+       char *identity;
+       char *ca_cert_file;
+       char *client_cert_file;
+       char *private_key_file;
+       char *private_key_passphrase;
+       char *phase2;
        DBusMessage *pending;
        guint timeout;
 };
@@ -1181,6 +1189,13 @@ static void service_free(gpointer user_data)
        g_free(service->name);
        g_free(service->passphrase);
        g_free(service->identifier);
+       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->phase2);
        g_free(service);
 }
 
@@ -1357,6 +1372,21 @@ char *connman_service_get_interface(struct connman_service *service)
 }
 
 /**
+ * connman_service_get_network:
+ * @service: service structure
+ *
+ * Get the service network
+ */
+struct connman_network *
+__connman_service_get_network(struct connman_service *service)
+{
+       if (service == NULL)
+               return NULL;
+
+       return service->network;
+}
+
+/**
  * connman_service_set_favorite:
  * @service: service structure
  * @favorite: favorite value
@@ -1386,6 +1416,33 @@ int connman_service_set_favorite(struct connman_service *service,
        return 0;
 }
 
+void __connman_service_set_string(struct connman_service *service,
+                                 const char *key, const char *value)
+{
+       if (g_str_equal(key, "EAP") == TRUE) {
+               g_free(service->eap);
+               service->eap = g_strdup(value);
+       } else if (g_str_equal(key, "Identity") == TRUE) {
+               g_free(service->identity);
+               service->identity = g_strdup(value);
+       } else if (g_str_equal(key, "CACertFile") == TRUE) {
+               g_free(service->ca_cert_file);
+               service->ca_cert_file = g_strdup(value);
+       } else if (g_str_equal(key, "ClientCertFile") == TRUE) {
+               g_free(service->client_cert_file);
+               service->client_cert_file = g_strdup(value);
+       } else if (g_str_equal(key, "PrivateKeyFile") == TRUE) {
+               g_free(service->private_key_file);
+               service->private_key_file = g_strdup(value);
+       } else if (g_str_equal(key, "PrivateKeyPassphrase") == TRUE) {
+               g_free(service->private_key_passphrase);
+               service->private_key_passphrase = g_strdup(value);
+       } else if (g_str_equal(key, "Phase2") == TRUE) {
+               g_free(service->phase2);
+               service->phase2 = g_strdup(value);
+       }
+}
+
 int __connman_service_indicate_state(struct connman_service *service,
                                        enum connman_service_state state)
 {