diff options
author | Yu Jiung <jiung.yu@samsung.com> | 2017-03-06 10:48:48 +0900 |
---|---|---|
committer | Jiung Yu <jiung.yu@samsung.com> | 2017-04-13 16:50:05 +0900 |
commit | 13294d79e3412a68c541fd6a22840bf85521a420 (patch) | |
tree | 0fbf7db7c24b4eeeecdc711f18ed011e7d4c58b1 /vpn/plugins/ipsec.c | |
parent | 7859b3f51163cdb798423679bf291ffe27eff988 (diff) | |
download | connman-13294d79e3412a68c541fd6a22840bf85521a420.tar.gz connman-13294d79e3412a68c541fd6a22840bf85521a420.tar.bz2 connman-13294d79e3412a68c541fd6a22840bf85521a420.zip |
Add processing request & response vici message with socketipsec
Change-Id: I06ff60de06fde1ac8f484b1eecf49afed6d02542
Signed-off-by: Yu jiung <jiung.yu@samsung.com>
Diffstat (limited to 'vpn/plugins/ipsec.c')
-rw-r--r-- | vpn/plugins/ipsec.c | 1001 |
1 files changed, 926 insertions, 75 deletions
diff --git a/vpn/plugins/ipsec.c b/vpn/plugins/ipsec.c index de66cea7..5e347704 100644 --- a/vpn/plugins/ipsec.c +++ b/vpn/plugins/ipsec.c @@ -26,9 +26,19 @@ #include <errno.h> #include <unistd.h> #include <stdio.h> +#include <sys/stat.h> #include <net/if.h> #include <glib.h> +#include <gio/gio.h> + +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/safestack.h> +#include <openssl/pkcs12.h> +#include <openssl/x509.h> +#include <openssl/conf.h> #define CONNMAN_API_SUBJECT_TO_CHANGE #include <connman/plugin.h> @@ -45,40 +55,62 @@ #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +typedef enum { + CERT_TYPE_NONE, + CERT_TYPE_DER, + CERT_TYPE_PEM, + CERT_TYPE_PKCS12, + CERT_TYPE_MAX, +} cert_type_e; + static DBusConnection *connection; +static VICIClient *vici_client; +static GFileMonitor* monitor; + +struct openssl_private_data { + EVP_PKEY *private_key; + X509 *local_cert; + STACK_OF(X509) *ca_certs; +}; + +struct ipsec_private_data { + struct vpn_provider *provider; + struct openssl_private_data openssl_data; + vpn_provider_connect_cb_t cb; + + void *user_data; +}; struct { const char *cm_opt; const char *vici_key; const char *subsection; - vici_section_add_element add_elem; + vici_add_element add_elem; } ipsec_conn_options[] = { - {"IPsec.Version", "version", NULL, vici_section_add_kv}, - {"IPsec.LeftAddrs", "local_addrs", NULL, vici_section_add_kvl}, - {"IPsec.RightAddrs", "remote_addrs", NULL, vici_section_add_kvl}, - - {"IPsec.LocalAuth", "auth", "local", vici_section_add_kv}, - {"IPsec.LocalCerts", "certs", "local", vici_section_add_kv}, - {"IPsec.LocalID", "id", "local", vici_section_add_kv}, - {"IPsec.LocalXauthID", "xauth_id", "local", vici_section_add_kv}, - {"IPsec.LocalXauthAuth", "auth", "local-xauth", vici_section_add_kv}, - {"IPsec.LocalXauthXauthID", "xauth_id", "local-xauth", vici_section_add_kv}, - {"IPsec.RemoteAuth", "auth", "remote", vici_section_add_kv}, - {"IPsec.RemoteCerts", "certs", "remote", vici_section_add_kv}, - {"IPsec.RemoteID", "id", "remote", vici_section_add_kv}, - {"IPsec.RemoteXauthID", "xauth_id", "remote", vici_section_add_kv}, - {"IPsec.RemoteXauthAuth", "auth", "remote-xauth", vici_section_add_kv}, - {"IPsec.RemoteXauthXauthID", "xauth_id", "remote-xauth", vici_section_add_kv}, - {"IPsec.ChildrenLocalTs", "local_ts", "children", vici_section_add_kvl}, - {"IPsec.ChildrenRemoteTs", "remote_ts", "children", vici_section_add_kvl}, + {"IPsec.Version", "version", NULL, vici_add_kv}, + {"IPsec.LeftAddrs", "local_addrs", NULL, vici_add_kvl}, + {"IPsec.RightAddrs", "remote_addrs", NULL, vici_add_kvl}, + + {"IPsec.LocalAuth", "auth", "local", vici_add_kv}, + {"IPsec.LocalID", "id", "local", vici_add_kv}, + {"IPsec.LocalXauthID", "xauth_id", "local", vici_add_kv}, + {"IPsec.LocalXauthAuth", "auth", "local-xauth", vici_add_kv}, + {"IPsec.LocalXauthXauthID", "xauth_id", "local-xauth", vici_add_kv}, + {"IPsec.RemoteAuth", "auth", "remote", vici_add_kv}, + {"IPsec.RemoteID", "id", "remote", vici_add_kv}, + {"IPsec.RemoteXauthID", "xauth_id", "remote", vici_add_kv}, + {"IPsec.RemoteXauthAuth", "auth", "remote-xauth", vici_add_kv}, + {"IPsec.RemoteXauthXauthID", "xauth_id", "remote-xauth", vici_add_kv}, + {"IPsec.ChildrenLocalTS", "local_ts", "children", vici_add_kvl}, + {"IPsec.ChildrenRemoteTS", "remote_ts", "children", vici_add_kvl}, }; struct { const char *cm_opt; const char *vici_type; } ipsec_shared_options[] = { - {"IPsec.IkeData", "data"}, - {"IPsec.IkeOwners", "owners"}, + {"IPsec.IKEData", "data"}, + {"IPsec.IKEOwners", "owners"}, {"IPsec.XauthData", "data"}, {"IPsec.XauthOwners", "owners"}, }; @@ -91,8 +123,345 @@ struct { {"IPsec.CertType", "type", NULL}, {"IPsec.CertFlag", "flag", NULL}, {"IPsec.CertData", "data", NULL}, + {"IPsec.CertPass", "data", NULL}, +}; + +struct { + const char *cm_opt; + const char *vici_type; +} ipsec_pkey_options[] = { + {"IPsec.PKeyType", "type"}, + {"IPsec.PKeyData", "data"}, +}; + +static const char *ikev1_esp_proposals [] ={ + "aes256-sha256", + "aes128-sha256", + "aes256-sha1", + "aes128-sha1", + "aes256-md5", + "aes128-md5", + "3des-sha1", + "3des-md5", + NULL, +}; + +static const char *ikev1_proposals [] ={ + "aes256-sha256-modp1024", + "aes128-sha256-modp1024", + "aes256-sha1-modp1024", + "aes128-sha1-modp1024", + "aes256-md5-modp1024", + "aes128-md5-modp1024", + "3des-sha1-modp1024", + "3des-md5-modp1024", + NULL, }; +static const char *ikev2_esp_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024"; + +static const char *ikev2_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024"; + +static void init_openssl(void) +{ + /* Load the human readable error strings for libcrypto */ +#if OPENSSL_API_COMPAT < 0x10100000L + /* TODO :remove this after debug */ + DBG("openssl version is under 1.01"); + ERR_load_crypto_strings(); +#else + /* As of version 1.1.0 OpenSSL will automatically allocate + * all resources that it needs so no explicit initialisation + * is required. Similarly it will also automatically + * deinitialise as required. */ + /* OPENSSL_init_crypto(); */ +#endif + /* Load all digest and cipher algorithms */ +#if OPENSSL_API_COMPAT < 0x10100000L + OpenSSL_add_all_algorithms(); +#else + /* As of version 1.1.0 OpenSSL will automatically allocate + * all resources that it needs so no explicit initialisation + * is required. Similarly it will also automatically + * deinitialise as required. */ + /* OPENSSL_init_crypto(); */ +#endif +#if OPENSSL_API_COMPAT < 0x10100000L + OPENSSL_config(NULL); +#else +#endif + /* TODO :remove this after debug */ + DBG("init openssl"); + return; +} + +static void deinit_openssl(void) +{ +#if OPENSSL_API_COMPAT < 0x10100000L + EVP_cleanup(); +#else +#endif +#if OPENSSL_API_COMPAT < 0x10100000L + ERR_free_strings(); +#else +#endif + return; +} + +static int print_openssl_error_cb(const char *str, size_t len, void *u) +{ + connman_error("%s", str); + return 0; +} + +static void print_openssl_error() +{ + ERR_print_errors_cb(print_openssl_error_cb, NULL); + return; +} + +static int get_cert_type(const char *path) +{ + char *down_str = NULL; + int cert_type; + + down_str = g_ascii_strdown(path, strlen(path)); + if (!down_str) + return CERT_TYPE_NONE; + + if(g_str_has_suffix(down_str, ".pem")) + cert_type = CERT_TYPE_PEM; + else if (g_str_has_suffix(down_str, ".der") || g_str_has_suffix(down_str, ".crt")) + cert_type = CERT_TYPE_DER; + else if (g_str_has_suffix(down_str, ".p12") || g_str_has_suffix(down_str, ".pfx")) + cert_type = CERT_TYPE_PKCS12; + else + cert_type = CERT_TYPE_NONE; + g_free(down_str); + + return cert_type; +} + +static void read_der_file(const char *path, X509 **cert) +{ + FILE *fp = NULL; + + DBG("der path %s\n", path); + fp = fopen(path, "r"); + *cert = d2i_X509_fp(fp, NULL); + fclose(fp); + return; +} + +static void read_pem_file(const char *path, X509 **cert) +{ + FILE *fp = NULL; + + DBG("pem path %s\n", path); + fp = fopen(path, "r"); + *cert = PEM_read_X509(fp, cert, NULL, NULL); + fclose(fp); + return; +} + +static void read_pkcs12_file(const char *path, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) +{ + FILE *fp = NULL; + PKCS12 *p12; + + DBG("pkcs12 path %s\n", path); + fp = fopen(path, "r"); + + p12 = d2i_PKCS12_fp(fp, NULL); + if (!p12) { + print_openssl_error(); + fclose(fp); + return; + } + + if (!PKCS12_parse(p12, pass, pkey, cert, ca)) { + print_openssl_error(); + fclose(fp); + return; + } + + PKCS12_free(p12); + return; +} + +static char *get_private_key_str(struct openssl_private_data *data) +{ + EVP_PKEY *pkey; + BIO* bio; + BUF_MEM *buf_ptr; + char *private_key_str = NULL; + + if (!data) + return NULL; + + if (!(pkey = data->private_key)) + return NULL; + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + print_openssl_error(); + return NULL; + } + + if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + BIO_get_mem_ptr(bio, &buf_ptr); + if (!buf_ptr) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + private_key_str = g_try_malloc0(buf_ptr->length + 1); + if (!private_key_str) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + g_strlcpy(private_key_str, buf_ptr->data, buf_ptr->length); + + BIO_free(bio); + + return private_key_str; +} + +static char *get_cert_str(X509 *cert) +{ + BIO* bio; + BUF_MEM *buf_ptr; + char *cert_str = NULL; + + if (!cert) + return NULL; + + bio = BIO_new(BIO_s_mem()); + if (!bio) { + print_openssl_error(); + return NULL; + } + + if (!PEM_write_bio_X509_AUX(bio, cert)) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + BIO_get_mem_ptr(bio, &buf_ptr); + if (!buf_ptr) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + cert_str = g_try_malloc0(buf_ptr->length + 1); + if (!cert_str) { + print_openssl_error(); + BIO_free(bio); + return NULL; + } + + g_strlcpy(cert_str, buf_ptr->data, buf_ptr->length); + + BIO_free(bio); + return cert_str; +} + +static char * get_local_cert_str(struct openssl_private_data *data) +{ + if (!data) + return NULL; + + if (!(data->local_cert)) + return NULL; + + return get_cert_str(data->local_cert); +} + +int get_ca_cert_num(struct openssl_private_data *data) +{ + if(!data || !data->ca_certs) + return 0; + + return sk_X509_num(data->ca_certs); +} + +static char * get_nth_ca_cert_str(struct openssl_private_data *data, int num) +{ + X509 *cert = NULL; + + if (!data) + return NULL; + + if (!(data->ca_certs)) + return NULL; + + cert = sk_X509_value(data->ca_certs, num); + + return get_cert_str(cert); +} + +static void extract_cert_info(const char *path, const char *pass, struct openssl_private_data *data) +{ + if(!path || !data) { + /* TODO :remove this after debug */ + DBG("there's no cert data"); + return; + } + + switch (get_cert_type(path)) { + case CERT_TYPE_DER: + read_der_file(path, &(data->local_cert)); + break; + case CERT_TYPE_PEM: + read_pem_file(path, &(data->local_cert)); + break; + case CERT_TYPE_PKCS12: + read_pkcs12_file(path, pass, &(data->private_key), &(data->local_cert), &(data->ca_certs)); + break; + default: + break; + } + + return; +} + +static void free_openssl_private_data(struct openssl_private_data *data) +{ + if (!data) + return; + + EVP_PKEY *private_key = data->private_key; + X509 *local_cert = data->local_cert; + STACK_OF(X509) *ca_certs = data->ca_certs; + + if (private_key) + EVP_PKEY_free(private_key); + + if (local_cert) + X509_free(local_cert); + + if (ca_certs) + sk_X509_pop_free(ca_certs, X509_free); + + return; +} + +static void free_private_data(struct ipsec_private_data *data) +{ + free_openssl_private_data(&(data->openssl_data)); + deinit_openssl(); + g_free(data); +} static int ipsec_notify(DBusMessage *msg, struct vpn_provider *provider) { @@ -109,41 +478,169 @@ static int ipsec_is_same_auth(const char* req, const char* target) static int vici_load_cert(const char* type, const char* flag, const char* data) { VICISection *sect; + int ret = 0; + sect = vici_create_section(NULL); - vici_section_add_kv(sect, "type", type, NULL); - vici_section_add_kv(sect, "flag", flag, NULL); - vici_section_add_kv(sect, "data", data, NULL); + if (!sect) + return -ENOMEM; - vici_client_send_request(VICI_REQUEST_LOAD_CERT, sect); + vici_add_kv(sect, "type", type, NULL); + vici_add_kv(sect, "flag", flag, NULL); + vici_add_kv(sect, "data", data, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_CERT, sect); + if (ret < 0) + connman_error("vici_send_request failed"); vici_destroy_section(sect); - return 0; + return ret; +} + +static int vici_load_key(const char* type, const char* data) +{ + VICISection *sect; + sect = vici_create_section(NULL); + int ret = 0; + + vici_add_kv(sect, "type", type, NULL); + vici_add_kv(sect, "data", data, NULL); + ret = vici_send_request(vici_client, VICI_CMD_LOAD_KEY, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static void ipsec_add_default_child_sa_data(struct vpn_provider *provider, VICISection *child) +{ + const char *version = vpn_provider_get_string(provider, "IPsec.Version"); + if (g_strcmp0(version, "1") == 0) { + int i = 0; + GSList *list; + + for (list = NULL; ikev1_esp_proposals[i] != NULL; i++) + list = g_slist_append(list, g_strdup(ikev1_esp_proposals[i])); + vici_add_list(child, "esp_proposals", list, "net"); + list = NULL; + } else { + vici_add_kvl(child, "esp_proposals", ikev2_esp_proposals, "net"); + } + return; } -static int ipsec_load_conn(struct vpn_provider *provider) +static void ipsec_add_default_conn_data(struct vpn_provider *provider, VICISection *conn) +{ + const char *version = vpn_provider_get_string(provider, "IPsec.Version"); + if (g_strcmp0(version, "1") == 0) { + int i = 0; + GSList *list; + + for (list = NULL; ikev1_proposals[i] != NULL; i++) + list = g_slist_append(list, g_strdup(ikev1_proposals[i])); + vici_add_list(conn, "proposals", list, NULL); + list = NULL; + + if (g_strcmp0(vpn_provider_get_string(provider, "IPsec.LocalAuth"), "psk") == 0) + vici_add_kv(conn, "aggressive", "yes", NULL); + + } else { + vici_add_kvl(conn, "proposals", ikev2_proposals, NULL); + } + + vici_add_kvl(conn, "vips", "0.0.0.0", NULL); + return; +} + + +static int ipsec_load_conn(struct vpn_provider *provider, struct ipsec_private_data *data) { const char *key; const char *value; const char *subsection; - VICISection *sect; + char *local_cert_str; + VICISection *conn; + VICISection *children; int i; + int ret = 0; + + if (!provider || !data) { + connman_error("invalid provider or data"); + return -EINVAL; + } value = vpn_provider_get_string(provider, "Name"); - sect = vici_create_section(value); + DBG("Name: %s", value); + conn = vici_create_section(value); + children = vici_create_section("children"); + add_subsection("children", children, conn); for (i = 0; i < (int)ARRAY_SIZE(ipsec_conn_options); i++) { - key = ipsec_conn_options[i].vici_key; value = vpn_provider_get_string(provider, ipsec_conn_options[i].cm_opt); + if (!value) + continue; + + key = ipsec_conn_options[i].vici_key; subsection = ipsec_conn_options[i].subsection; - ipsec_conn_options[i].add_elem(sect, key, value, subsection); + ipsec_conn_options[i].add_elem(conn, key, value, subsection); } - vici_client_send_request(VICI_REQUEST_LOAD_CONN, sect); + local_cert_str = get_local_cert_str(&(data->openssl_data)); + if (local_cert_str) { + /* TODO :remove this after debug */ + DBG("There's local certification to add local section"); + vici_add_kvl(conn, "certs", local_cert_str, "local"); + g_free(local_cert_str); + } - vici_destroy_section(sect); + ipsec_add_default_conn_data(provider, conn); + ipsec_add_default_child_sa_data(provider, children); - return 0; + ret = vici_send_request(vici_client, VICI_CMD_LOAD_CONN, conn); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(conn); + + return ret; +} + +static int ipsec_load_private_data(struct ipsec_private_data *data) +{ + char *private_key_str; + char *ca_cert_str; + int ca_cert_num; + int i; + int ret = 0; + + private_key_str = get_private_key_str(&(data->openssl_data)); + if (private_key_str) { + /* TODO :remove this after debug */ + DBG("load private key"); + ret = vici_load_key("RSA", private_key_str); + g_free(private_key_str); + } + + if (ret < 0) + return ret; + + ca_cert_num = get_ca_cert_num(&(data->openssl_data)); + if (ca_cert_num < 1) + return 0; + + for (i = 0; i < ca_cert_num; i++) { + /* TODO :remove this after debug */ + DBG("load CA cert"); + ca_cert_str = get_nth_ca_cert_str(&(data->openssl_data), i); + ret = vici_load_cert("X509", "CA", ca_cert_str); + g_free(ca_cert_str); + if (ret < 0) + return ret; + } + + return ret; } static int ipsec_load_shared_psk(struct vpn_provider *provider) @@ -151,122 +648,399 @@ static int ipsec_load_shared_psk(struct vpn_provider *provider) const char *data; const char *owner; VICISection *sect; + int ret = 0; - data = vpn_provider_get_string(provider, "IPsec.IkeData"); - owner = vpn_provider_get_string(provider, "IPsec.IkeOwners"); + if (!provider) { + connman_error("invalid provider"); + ret = -EINVAL; + } + + data = vpn_provider_get_string(provider, "IPsec.IKEData"); + owner = vpn_provider_get_string(provider, "IPsec.IKEOwners"); + DBG("IKEData: %s, IKEOwners: %s", data, owner); if (!data) return 0; sect = vici_create_section(NULL); + if (!sect) { + return -ENOMEM; + } - vici_section_add_kv(sect, "type", VICI_SHARED_TYPE_PSK, NULL); - vici_section_add_kv(sect, "data", data, NULL); - vici_section_add_kvl(sect, "owners", owner, NULL); + vici_add_kv(sect, "type", VICI_SHARED_TYPE_PSK, NULL); + vici_add_kv(sect, "data", data, NULL); + vici_add_kvl(sect, "owners", owner, NULL); - vici_client_send_request(VICI_REQUEST_LOAD_SHARED, sect); + ret = vici_send_request(vici_client, VICI_CMD_LOAD_SHARED, sect); + if (ret < 0) + connman_error("vici_send_request failed"); vici_destroy_section(sect); - return 0; + return ret; } - static int ipsec_load_shared_xauth(struct vpn_provider *provider) { const char *data; const char *owner; VICISection *sect; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } data = vpn_provider_get_string(provider, "IPsec.XauthData"); owner = vpn_provider_get_string(provider, "IPsec.XauthOwners"); + DBG("XauthData: %s, XauthOwners: %s", data, owner); if (!data) return 0; sect = vici_create_section(NULL); - vici_section_add_kv(sect, "type", VICI_SHARED_TYPE_XAUTH, NULL); - vici_section_add_kv(sect, "data", data, NULL); - vici_section_add_kvl(sect, "owners", owner, NULL); + vici_add_kv(sect, "type", VICI_SHARED_TYPE_XAUTH, NULL); + vici_add_kv(sect, "data", data, NULL); + vici_add_kvl(sect, "owners", owner, NULL); - vici_client_send_request(VICI_REQUEST_LOAD_SHARED, sect); + ret = vici_send_request(vici_client, VICI_CMD_LOAD_SHARED, sect); + if (ret < 0) + connman_error("vici_send_request failed"); vici_destroy_section(sect); - return 0; + return ret; +} + +static char *load_file_from_path(const char *path) +{ + struct stat st; + FILE *fp = NULL; + int fd = 0; + unsigned long long file_size = 0; + char *file_buff = NULL; + + if (file_buff) { + connman_error("File path is NULL\n"); + return NULL; + } + + fp = fopen(path, "rb"); + if (!fp) { + connman_error("fopen %s is failed\n", path); + return NULL; + } + + fd = fileno(fp); + fstat(fd, &st); + file_size = st.st_size; + file_buff = g_try_malloc0(sizeof(char)*st.st_size); + if (file_buff == NULL) { + connman_error("g_try_malloc0 failed\n"); + fclose(fp); + return NULL; + } + + if (fread(file_buff, 1, file_size, fp) != file_size) { + connman_error("file size not matched\n"); + g_free(file_buff); + file_buff = NULL; + } + + fclose(fp); + return file_buff; +} + +static int ipsec_load_key(struct vpn_provider *provider) +{ + const char *type; + const char *path; + char *data; + VICISection *sect; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } + + type = vpn_provider_get_string(provider, "IPsec.PKeyType"); + path = vpn_provider_get_string(provider, "IPsec.PKeyData"); + DBG("PKeyType: %s, PKeyData: %s", type, path); + + if (!type || !path) + return 0; + + data = load_file_from_path(path); + if (!data) + return 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "type", type, NULL); + vici_add_kv(sect, "data", data, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_KEY, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + g_free(data); + + return ret; +} + +static int ipsec_initiate(struct vpn_provider *provider) +{ + VICISection *sect; + int ret = 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "child", "net", NULL); + ret = vici_send_request(vici_client, VICI_CMD_INITIATE, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; } static int ipsec_load_cert(struct vpn_provider *provider) { const char *type; const char *flag; - const char *data; - const char *auth_type; - int i; + char *data; + const char *local_auth_type; + const char *remote_auth_type; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } - auth_type = vpn_provider_get_string(provider, "IPsec.LocalAuth"); - if (!ipsec_is_same_auth(auth_type, IPSEC_AUTH_RSA)) { - connman_error("invalid auth type: %s", auth_type); - return -1; + local_auth_type = vpn_provider_get_string(provider, "IPsec.LocalAuth"); + remote_auth_type = vpn_provider_get_string(provider, "IPsec.RemoteAuth"); + if (!ipsec_is_same_auth(local_auth_type, "pubkey") && + !ipsec_is_same_auth(remote_auth_type, "pubkey")) { + DBG("invalid auth type"); + return 0; } - for (i = 0; i < (int)ARRAY_SIZE(ipsec_cert_options); i++) { - type = ipsec_cert_options[i].vici_type;; - flag = ipsec_cert_options[i].vici_flag; - data = vpn_provider_get_string(provider, ipsec_cert_options[i].cm_opt); - vici_load_cert(type, flag, data); + type = vpn_provider_get_string(provider, "IPsec.CertType"); + flag = vpn_provider_get_string(provider, "IPsec.CertFlag"); + data = load_file_from_path(vpn_provider_get_string(provider, "IPsec.CertData")); + DBG("CertType: %s, CertFalg: %s,CertData: %s", type, flag, data); + + ret = vici_load_cert(type, flag, data); + if (ret < 0) + connman_error("failed to load cert"); + + g_free(data); + + return ret; +} + +void connect_reply_cb(int err, void *user_data) +{ + struct ipsec_private_data *data; + + data = (struct ipsec_private_data *)user_data; + data->cb(data->provider, data->user_data, err); + + free_private_data(data); +} + +static struct ipsec_private_data* create_ipsec_private_data(struct vpn_provider *provider, + vpn_provider_connect_cb_t cb, void* user_data) +{ + struct ipsec_private_data *data; + data = g_try_new0(struct ipsec_private_data, 1); + if (!data) { + connman_error("out of memory"); + return NULL; } - return 0; + init_openssl(); + + data->provider = provider; + data->cb = cb; + data->user_data = user_data; + return data; } -static int ipsec_connect(struct vpn_provider *provider, - struct connman_task *task, const char *if_name, - vpn_provider_connect_cb_t cb, const char *dbus_sender, - void *user_data) +static void vici_connect(struct ipsec_private_data *data) { + struct vpn_provider *provider = NULL; + vpn_provider_connect_cb_t cb = NULL; int err = 0; - /* - * Start charon daemon using ipsec script of strongSwan. - */ - connman_task_add_argument(task, "start", NULL); - err = connman_task_run(task, vpn_died, provider, NULL, NULL, NULL); - IPSEC_ERROR_CHECK_GOTO(err, done, "ipsec start failed"); + if (!data) + IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid data parameter"); + + provider = data->provider; + cb = data->cb; + if (!provider || !cb) + IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid provider or callback"); + + DBG("data %p, provider %p", data, provider); /* * Initialize vici client */ - err = vici_client_initialize(); + err = vici_initialize(&vici_client); IPSEC_ERROR_CHECK_GOTO(err, done, "failed to initialize vici_client"); + /* TODO :remove this after debug */ + DBG("success to initialize vici socket"); + + vici_set_connect_reply_cb(vici_client, (vici_connect_reply_cb)connect_reply_cb, data); + /* * Send the load-conn command */ - err = ipsec_load_conn(provider); + err = ipsec_load_conn(provider, data); IPSEC_ERROR_CHECK_GOTO(err, done, "load-conn failed"); + /* TODO :remove this after debug */ + DBG("success to ipsec_load_conn"); + + err = ipsec_load_private_data(data); + IPSEC_ERROR_CHECK_GOTO(err, done, "load private data failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_private_data"); + /* * Send the load-shared command for PSK */ err = ipsec_load_shared_psk(provider); IPSEC_ERROR_CHECK_GOTO(err, done, "load-shared failed"); + /* TODO :remove this after debug */ + DBG("success to ipsec_load_shared_psk"); + /* * Send the load-shared command for XAUTH */ err = ipsec_load_shared_xauth(provider); IPSEC_ERROR_CHECK_GOTO(err, done, "load-shared failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_shared_xauth"); /* * Send the load-cert command */ err = ipsec_load_cert(provider); IPSEC_ERROR_CHECK_GOTO(err, done, "load-cert failed"); + /* TODO :remove this after debug */ + DBG("success to ipsec_load_cert"); + + /* + * Send the load-key command + */ + err = ipsec_load_key(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-key failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_cert"); + /* + * Send the initiate command + */ + err = ipsec_initiate(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "initiate failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_initiate"); + done: - if (cb) - cb(provider, user_data, err); + /* refer to connect_cb on vpn-provider.c for cb */ + if(err != 0 && cb) + cb(provider, data->user_data, -err); + + return; +} + +static void monitor_changed(GFileMonitor *monitor, GFile *file, GFile *other_file, + GFileMonitorEvent event_type, gpointer user_data) +{ + DBG("file %s", g_file_get_path(file)); + if (event_type == G_FILE_MONITOR_EVENT_CREATED) { + if (g_file_test(VICI_DEFAULT_URI, G_FILE_TEST_EXISTS)) { + DBG("file created: %s", VICI_DEFAULT_URI); + struct ipsec_private_data *data = user_data; + vici_connect(data); + g_object_unref(monitor); + } + } +} + +static void monitor_vici_socket(struct ipsec_private_data *data) +{ + GError *error = NULL; + GFile* file; + + file = g_file_new_for_path(VICI_DEFAULT_URI); + monitor = g_file_monitor_file(file, G_FILE_MONITOR_SEND_MOVED, NULL, &error); + if (error) { + connman_error("g_file_monitor_directory failed: %s / %d", error->message, error->code); + g_error_free(error); + return; + } + /* TODO :remove this after debug */ + DBG("starting to monitor vici socket"); + g_signal_connect(monitor, "changed", G_CALLBACK(monitor_changed), data); + g_object_unref(file); +} + +static void check_vici_socket(struct ipsec_private_data *data) +{ + DBG("data %p", data); + if (g_file_test(VICI_DEFAULT_URI, G_FILE_TEST_EXISTS)) { + DBG("file exists: %s", VICI_DEFAULT_URI); + vici_connect(data); + } else { + monitor_vici_socket(data); + } +} + +static int ipsec_connect(struct vpn_provider *provider, + struct connman_task *task, const char *if_name, + vpn_provider_connect_cb_t cb, const char *dbus_sender, + void *user_data) +{ + struct ipsec_private_data *data; + const char *path; + const char *pass; + int err = 0; + + data = create_ipsec_private_data(provider, cb, user_data); + /* + * Start charon daemon using ipsec script of strongSwan. + */ + err = connman_task_run(task, vpn_died, provider, NULL, NULL, NULL); + if (err < 0) { + connman_error("charon start failed"); + if (cb) + cb(provider, user_data, err); + return err; + } + + path = vpn_provider_get_string(provider, "IPsec.LocalCerts"); + pass = vpn_provider_get_string(provider, "IPsec.LocalCertPass"); + extract_cert_info(path, pass, &(data->openssl_data)); + + check_vici_socket(data); +// g_usleep(G_USEC_PER_SEC); return err; } @@ -278,6 +1052,83 @@ static int ipsec_error_code(struct vpn_provider *provider, int exit_code) static int ipsec_save(struct vpn_provider *provider, GKeyFile *keyfile) { + int i; + const char *option; + + DBG(""); + /* + * Save IKE connection configurations + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_conn_options); i++) { + option = vpn_provider_get_string(provider, ipsec_conn_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_conn_options[i].cm_opt, + option); + } + + /* + * Save shared IKE PSK, EAP or XAUTH secret + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_shared_options); i++) { + option = vpn_provider_get_string(provider, ipsec_shared_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_shared_options[i].cm_opt, + option); + } + + /* + * Save certification + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_cert_options); i++) { + option = vpn_provider_get_string(provider, ipsec_cert_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_cert_options[i].cm_opt, + option); + } + + /* + * Save private key + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_pkey_options); i++) { + option = vpn_provider_get_string(provider, ipsec_pkey_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_pkey_options[i].cm_opt, + option); + } + + /* + * Save local certification + */ + option = vpn_provider_get_string(provider, "IPsec.LocalCerts"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.LocalCerts", + option); + option = vpn_provider_get_string(provider, "IPsec.LocalCertPass"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.LocalCertPass", + option); + /* + * Save CA certification directory + */ + option = vpn_provider_get_string(provider, "IPsec.CACertsDir"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.CACertsDir", + option); + return 0; } @@ -285,7 +1136,7 @@ static void ipsec_disconnect(struct vpn_provider *provider) { int err = 0; - err = vici_client_deinitialize(); + err = vici_deinitialize(vici_client); IPSEC_ERROR_CHECK_RETURN(err, "failed to deinitialize vici_client"); } |