summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMakefile.am2
-rwxr-xr-xMakefile.plugins4
-rwxr-xr-xconfigure.ac8
-rw-r--r--doc/vpn-config-format.txt4
-rwxr-xr-xpackaging/connman.spec3
-rwxr-xr-xsrc/log.c2
-rw-r--r--vpn/plugins/ipsec.c1001
-rw-r--r--vpn/plugins/ipsec.h3
-rw-r--r--vpn/plugins/vici-client.c821
-rw-r--r--vpn/plugins/vici-client.h49
-rwxr-xr-xvpn/plugins/vpn.c97
-rwxr-xr-xvpn/plugins/vpn.h3
-rwxr-xr-xvpn/vpn-config.c14
-rwxr-xr-xvpn/vpn-provider.c23
-rwxr-xr-xvpn/vpn.h5
15 files changed, 1800 insertions, 239 deletions
diff --git a/Makefile.am b/Makefile.am
index e287363c..9fd16a0d 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -155,7 +155,7 @@ vpn_connman_vpnd_SOURCES = $(gdhcp_sources) $(builtin_vpn_sources) \
vpn_connman_vpnd_LDADD = gdbus/libgdbus-internal.la $(builtin_vpn_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @XTABLES_LIBS@ @GNUTLS_LIBS@ \
- @TPKP_GNUTLS_LIBS@ @LIBSYSTEMD_LIBS@\
+ @TPKP_GNUTLS_LIBS@ @LIBSYSTEMD_LIBS@ \
-lresolv -ldl
vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \
diff --git a/Makefile.plugins b/Makefile.plugins
index e1c0a11c..a7452622 100755
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -122,8 +122,8 @@ vpn_plugins_ipsec_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
vpn/plugins/ipsec.c vpn/plugins/vici-client.c
vpn_plugins_ipsec_la_CFLAGS = $(plugin_cflags) -DIPSEC=\"@IPSEC@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
- -DSCRIPTDIR=\""$(build_scriptdir)"\"
-vpn_plugins_ipsec_la_LDFLAGS = $(plugin_ldflags)
+ -DSCRIPTDIR=\""$(build_scriptdir)"\" @GIO_CFLAGS@ @OPENSSL_CFLAGS@
+vpn_plugins_ipsec_la_LDFLAGS = $(plugin_ldflags) @GIO_LIBS@ @OPENSSL_LIBS@
endif
endif
diff --git a/configure.ac b/configure.ac
index 95aa0a4f..cd2013f4 100755
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,14 @@ AC_ARG_ENABLE(ipsec,
AC_HELP_STRING([--enable-ipsec], [enable ipsec support]),
[enable_ipsec=${enableval}], [enable_ipsec="no"])
if (test "${enable_ipsec}" != "no"); then
+ PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.28, dummy=yes,
+ AC_MSG_ERROR(GIO >= 2.28 is required))
+ AC_SUBST(GIO_CFLAGS)
+ AC_SUBST(GIO_LIBS)
+ PKG_CHECK_MODULES(OPENSSL, openssl, dummy=yes,
+ AC_MSG_ERROR(openssl library is required))
+ AC_SUBST(OPENSSL_CFLAGS)
+ AC_SUBST(OPENSSL_LIBS)
if (test -z "${path_ipsec}"); then
AC_PATH_PROG(IPSEC, [charon], [/usr/bin/charon], $PATH:/usr/bin)
if (test -z "${IPSEC}"); then
diff --git a/doc/vpn-config-format.txt b/doc/vpn-config-format.txt
index 15d3a261..b4898eb0 100644
--- a/doc/vpn-config-format.txt
+++ b/doc/vpn-config-format.txt
@@ -216,8 +216,8 @@ IPsec VPN supports following options (see swanctl.conf(5) for details):
IPsec.ChildrenLocalTs children.local_ts local selectors to include in CHILD_SA (O)
IPsec.ChildrenRemoteTs children.remote_ts Remote selectors to include in CHILD_SA (O)
- IPsec.IkeData secret.data IKE PSK raw shared key data
- IPsec.IkeOwners secret.Owners list of shared key owner identities
+ IPsec.IKEData secret.data IKE PSK raw shared key data
+ IPsec.IKEOwners secret.Owners list of shared key owner identities
IPsec.XauthData secret.data XAUTH raw shared key data
IPsec.XauthOwners secret.Owners list of shared key owner identities
diff --git a/packaging/connman.spec b/packaging/connman.spec
index 2b7dfd42..6cf5b37d 100755
--- a/packaging/connman.spec
+++ b/packaging/connman.spec
@@ -14,6 +14,7 @@ Source0: %{name}-%{version}.tar.gz
BuildRequires: systemd-devel
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(libiptc)
BuildRequires: pkgconfig(xtables)
BuildRequires: pkgconfig(libsmack)
@@ -27,6 +28,7 @@ BuildRequires: openvpn
%endif
%if %{with connman_ipsec}
BuildRequires: strongswan
+BuildRequires: pkgconfig(openssl)
%endif
BuildRequires: ca-certificates-devel
BuildRequires: readline-devel
@@ -73,6 +75,7 @@ OpenVPN support for Connman.
Summary: IPsec Support for Connman
Requires: %{name} = %{version}
Requires: strongswan
+BuildRequires: pkgconfig(openssl)
%description plugin-ipsec
OpenVPN support for Connman.
diff --git a/src/log.c b/src/log.c
index 1dbd41a3..7a8e7c62 100755
--- a/src/log.c
+++ b/src/log.c
@@ -216,6 +216,7 @@ void connman_error(const char *format, ...)
vsyslog(LOG_ERR, format, ap);
va_end(ap);
+ fflush(log_file);
}
/**
@@ -234,6 +235,7 @@ void connman_debug(const char *format, ...)
vsyslog(LOG_DEBUG, format, ap);
va_end(ap);
+ fflush(log_file);
}
static void print_backtrace(unsigned int offset)
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");
}
diff --git a/vpn/plugins/ipsec.h b/vpn/plugins/ipsec.h
index 0081a439..6fe50a09 100644
--- a/vpn/plugins/ipsec.h
+++ b/vpn/plugins/ipsec.h
@@ -6,12 +6,11 @@
#define IPSEC_AUTH_XAUTH "XAUTH"
#define VICI_SHARED_TYPE_PSK "IKE"
-#define VICI_SHARED_TYPE_XAUTH "XAUTH"
+#define VICI_SHARED_TYPE_XAUTH "xauth"
#define IPSEC_ERROR_CHECK_GOTO(err, target, fmt, arg...) do { \
if (err < 0) { \
connman_error(fmt, ## arg); \
- err = -1; \
goto target; \
} \
} while (0)
diff --git a/vpn/plugins/vici-client.c b/vpn/plugins/vici-client.c
index dbf14084..6513367f 100644
--- a/vpn/plugins/vici-client.c
+++ b/vpn/plugins/vici-client.c
@@ -1,11 +1,14 @@
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <sys/stat.h>
#include <arpa/inet.h>
#include <glib.h>
@@ -14,8 +17,6 @@
#include "ipsec.h"
#include "vici-client.h"
-#define VICI_DEFAULT_URI "/var/run/charon.vici"
-
#define SOCK_FD_MIN 3
#define VICI_REQUEST_TIMEOUT 5000
@@ -40,28 +41,38 @@ enum vici_packet_type {
VICI_EVENT = 7,
};
-typedef void (*process_return)(unsigned char *buf, unsigned int size);
+static const char *vici_cmd_str[] = {
+ "load-conn",
+ "load-shared",
+ "load-cert",
+ "load-authority",
+ "unload-authority",
+ "load-key",
+ "initiate",
+ NULL,
+};
struct request {
unsigned int allocated;
unsigned int used;
unsigned int hdr_len;
- char *buf;
+ char *sndbuf;
+ int cmd;
int err;
- int client_source_idle_id;
- int client_source_timeout_id;
/* process reply */
unsigned int rcv_pkt_size;
- process_return handler;
+ char *rcvbuf;
/* davici_cb cb; */
void *user;
};
struct _VICIClient {
/* io data */
- int client_sock;
+ int client_sock_fd;
int client_watch;
- GList *request_list;
+ GSList *request_list;
+ vici_connect_reply_cb reply;
+ void *ipsec_user_data;
};
struct _VICISection {
@@ -71,7 +82,7 @@ struct _VICISection {
GHashTable *subsection;
};
-static void _remove_list(gpointer data)
+static void remove_list(gpointer data)
{
if (data == NULL)
return;
@@ -88,7 +99,7 @@ void vici_destroy_section(VICISection* section)
g_free(section);
}
-static void _free_section(gpointer data)
+static void free_section(gpointer data)
{
VICISection* section = (VICISection*)data;
vici_destroy_section(section);
@@ -107,66 +118,65 @@ VICISection* vici_create_section(const char* name)
if (name)
section->name = g_strdup(name);
section->kvs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
- section->kvls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _remove_list);
- section->subsection = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _free_section);
+ section->kvls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, remove_list);
+ section->subsection = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_section);
return section;
}
-static int _vici_section_add_kvl(VICISection* section, const char* key, const char* value)
+int add_subsection(const char* name, VICISection* child, VICISection* section)
{
- GSList *list = NULL;
- if (section == NULL || key == NULL || value == NULL) {
+ if (section == NULL || name == NULL || child == NULL) {
connman_error("invalid parameter");
return -1;
}
- list = g_hash_table_lookup(section->kvls, key);
- if (list == NULL) {
- list = g_slist_alloc();
- g_hash_table_insert(section->kvls, g_strdup(key), list);
- }
-
- list = g_slist_prepend(list, g_strdup(value));
-
+ g_hash_table_insert(section->subsection, g_strdup(name), child);
return 0;
}
-static int _vici_section_add_kv(VICISection* section, const char* key, const char* value)
+static int add_kvl_to_section(const char* key, const char* value, VICISection* section)
{
+ GSList *list = NULL;
if (section == NULL || key == NULL || value == NULL) {
connman_error("invalid parameter");
return -1;
}
- g_hash_table_insert(section->kvs, g_strdup(key), g_strdup(value));
+ list = g_hash_table_lookup(section->kvls, key);
+ if (list == NULL)
+ list = g_slist_alloc();
+
+ list = g_slist_prepend(list, g_strdup(value));
+ g_hash_table_replace(section->kvls, g_strdup(key), list);
return 0;
}
-static int vici_section_add_subsection(VICISection* section, const char* name, VICISection* child)
+static int add_kv_to_section(const char* key, const char* value, VICISection* section)
{
- if (section == NULL || name == NULL || child == NULL) {
+ if (section == NULL || key == NULL || value == NULL) {
connman_error("invalid parameter");
return -1;
}
- g_hash_table_insert(section->subsection, g_strdup(name), child);
+ g_hash_table_insert(section->kvs, g_strdup(key), g_strdup(value));
return 0;
}
-static VICISection* _vici_section_get_subsection(VICISection* section, const char* name)
+static VICISection* get_subsection(VICISection* section, const char* name)
{
VICISection* sub = g_hash_table_lookup(section->subsection, name);
if (sub == NULL) {
sub = vici_create_section(name);
- vici_section_add_subsection(section, name, sub);
+ add_subsection(name, sub, section);
}
return sub;
}
-int vici_section_add_kv(VICISection* section, const char* key,
+int vici_add_kv(VICISection* section, const char* key,
const char* value, const char* subsection)
{
VICISection* target = section;
+ DBG("key: %s, value: %s, subsection: %s", key, value, subsection);
if (section == NULL || key == NULL) {
connman_error("invalid parameter");
@@ -174,77 +184,170 @@ int vici_section_add_kv(VICISection* section, const char* key,
}
if (subsection)
- target = _vici_section_get_subsection(section, subsection);
+ target = get_subsection(section, subsection);
- _vici_section_add_kv(target, key, value);
+ add_kv_to_section(key, value, target);
return 0;
}
-int vici_section_add_kvl(VICISection* section, const char* key,
+int vici_add_kvl(VICISection* section, const char* key,
const char* value, const char* subsection)
{
VICISection* target = section;
+ DBG("key: %s, value: %s, subsection: %s", key, value, subsection);
+ if (section == NULL || key == NULL) {
+ connman_error("invalid parameter");
+ return -1;
+ }
+
+ if (subsection)
+ target = get_subsection(section, subsection);
+
+ if (g_strcmp0(subsection, "children") == 0)
+ target = get_subsection(target, "net");
+
+ add_kvl_to_section(key, value, target);
+ return 0;
+}
+
+static void add_list_to_section(char *key, GSList *list, VICISection *section)
+{
+ if (section == NULL || key == NULL || list == NULL)
+ return;
+
+ g_hash_table_insert(section->kvls, g_strdup(key), g_slist_copy(list));
+ return;
+}
+
+int vici_add_list(VICISection* section, char *key, GSList *list, const char* subsection)
+{
+ VICISection* target = section;
+
+ DBG("key: %s, subsection: %s", key, subsection);
if (section == NULL || key == NULL) {
connman_error("invalid parameter");
return -1;
}
if (subsection)
- target = _vici_section_get_subsection(section, subsection);
+ target = get_subsection(section, subsection);
- _vici_section_add_kvl(target, key, value);
+ if (g_strcmp0(subsection, "children") == 0)
+ target = get_subsection(target, "net");
+
+ add_list_to_section(key, list, target);
return 0;
}
-static void* _add_element(struct request *r, enum vici_element type,
+static char *load_cert_from_path(const char *path)
+{
+ struct stat st;
+ FILE *fp = NULL;
+ int fd = 0;
+ unsigned long long file_size = 0;
+ char *file_buff = NULL;
+
+ fp = fopen(path, "rb");
+ 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;
+}
+
+int vici_add_cert_kv(VICISection *section, const char *key,
+ const char *value, const char *subsection)
+{
+ char *cert = NULL;
+ int ret = 0;
+
+ if (value == NULL) {
+ DBG("value is null");
+ return 0;
+ }
+
+ cert = load_cert_from_path(value);
+ if (!cert)
+ return -1;
+
+ ret = vici_add_kv(section, key, (const char *)cert, subsection);
+ g_free(cert);
+ return ret;
+}
+
+int vici_add_cert_kvl(VICISection *section, const char *key,
+ const char *value, const char *subsection)
+{
+ char *cert = NULL;
+ int ret = 0;
+
+ cert = load_cert_from_path(value);
+ if (!cert)
+ return -1;
+
+ ret = vici_add_kvl(section, key, (const char *)cert, subsection);
+ g_free(cert);
+ return ret;
+}
+
+static void *add_element(struct request *r, enum vici_element type,
unsigned int size)
{
unsigned int newlen;
void *ret, *new;
- if (r->used + size + 1 > r->allocated)
- {
+ if (r->used + size + 1 > r->allocated) {
newlen = r->allocated;
- while (newlen < r->used + size + 1)
- {
+ while (newlen < r->used + size + 1) {
newlen *= 2;
}
- new = realloc(r->buf, newlen);
- if (!new)
- {
+ new = realloc(r->sndbuf, newlen);
+ if (!new) {
r->err = -errno;
return NULL;
}
- r->buf = new;
+ r->sndbuf = new;
r->allocated = newlen;
}
- r->buf[r->used++] = type;
- ret = r->buf + r->used;
+ r->sndbuf[r->used++] = type;
+ ret = r->sndbuf + r->used;
r->used += size;
return ret;
}
-static void vici_section_start(struct request *r, const char *name)
+static void section_start(struct request *r, const char *name)
{
uint8_t nlen;
char *pos;
nlen = strlen(name);
- pos = _add_element(r, VICI_SECTION_START, 1 + nlen);
- if (pos)
- {
+ pos = add_element(r, VICI_SECTION_START, 1 + nlen);
+ if (pos) {
pos[0] = nlen;
memcpy(pos + 1, name, nlen);
}
}
-static void vici_section_end(struct request *r)
+static void section_end(struct request *r)
{
- _add_element(r, VICI_SECTION_END, 0);
+ add_element(r, VICI_SECTION_END, 0);
}
-static void vici_kv(struct request *r, const char *name,
+static void key_value(struct request *r, const char *name,
const void *buf, unsigned int buflen)
{
uint8_t nlen;
@@ -252,9 +355,8 @@ static void vici_kv(struct request *r, const char *name,
char *pos;
nlen = strlen(name);
- pos = _add_element(r, VICI_KEY_VALUE, 1 + nlen + sizeof(vlen) + buflen);
- if (pos)
- {
+ pos = add_element(r, VICI_KEY_VALUE, 1 + nlen + sizeof(vlen) + buflen);
+ if (pos) {
pos[0] = nlen;
memcpy(pos + 1, name, nlen);
vlen = htons(buflen);
@@ -264,66 +366,78 @@ static void vici_kv(struct request *r, const char *name,
}
-static void vici_list_start(struct request *r, const char *name)
+static void list_start(struct request *r, const char *name)
{
uint8_t nlen;
char *pos;
nlen = strlen(name);
- pos = _add_element(r, VICI_LIST_START, 1 + nlen);
- if (pos)
- {
+ pos = add_element(r, VICI_LIST_START, 1 + nlen);
+ if (pos) {
pos[0] = nlen;
memcpy(pos + 1, name, nlen);
}
}
-static void vici_list_item(struct request *r, const void *buf,
+static void list_item(struct request *r, const void *buf,
unsigned int buflen)
{
uint16_t vlen;
char *pos;
- pos = _add_element(r, VICI_LIST_ITEM, sizeof(vlen) + buflen);
- if (pos)
- {
+ pos = add_element(r, VICI_LIST_ITEM, sizeof(vlen) + buflen);
+ if (pos) {
vlen = htons(buflen);
memcpy(pos, &vlen, sizeof(vlen));
memcpy(pos + sizeof(vlen), buf, buflen);
}
}
-static void vici_list_end(struct request *r)
+static void list_end(struct request *r)
{
- _add_element(r, VICI_LIST_END, 0);
+ add_element(r, VICI_LIST_END, 0);
}
+static void destroy_vici_request(gpointer data)
+{
+ struct request *req = (struct request *)data;
+ if(!req)
+ return;
+
+ g_free(req->sndbuf);
+ g_free(req->rcvbuf);
+ g_free(req);
+}
-static int create_vici_request(enum vici_packet_type type, const char *name,
+static int create_vici_request(enum vici_packet_type type, VICIClientCmd cmd,
struct request **rp)
{
struct request *req = NULL;
- if (!name || !rp)
- return -1;
+ if (cmd >= VICI_CMD_MAX || !rp)
+ return -EINVAL;
req = g_try_new0(struct request, 1);
- if (!req)
- return -1;
+ if (!req) {
+ connman_error("g_try_new0 failed");
+ return -ENOMEM;
+ }
req->used = 2;
- req->used += strlen(name);
+ req->used += strlen(vici_cmd_str[cmd]);
req->allocated = MIN(32, req->used);
- req->buf = g_try_new0(char, req->allocated);
- if (!req->buf) {
+ req->sndbuf = g_try_new0(char, req->allocated);
+ if (!req->sndbuf) {
+ connman_error("g_try_new0 failed");
g_free(req);
- return -1;
+ return -ENOMEM;
}
- req->buf[0] = type;
- req->buf[1] = req->used - 2; /* except for type and name length */
- memcpy(req->buf + 2, name, req->used - 2);
+ req->sndbuf[0] = type;
+ req->sndbuf[1] = req->used - 2; /* except for type and name length */
+ memcpy(req->sndbuf + 2, vici_cmd_str[cmd], req->used - 2);
req->hdr_len = req->used;
+ req->cmd = cmd;
*rp = req;
@@ -339,17 +453,16 @@ static void write_section_kvs(VICISection *section, struct request *req)
return;
g_hash_table_iter_init (&iter, section->kvs);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
if (!key || !value)
continue;
- vici_kv(req, (const char*)key, (const void *)value, strlen((char *)value));
+ key_value(req, (const char*)key, (const void *)value, strlen((char *)value));
}
return;
}
-static void _write_vl(gpointer data, gpointer user_data)
+static void write_list_item(gpointer data, gpointer user_data)
{
struct request *req = NULL;
char *value = NULL;
@@ -359,7 +472,7 @@ static void _write_vl(gpointer data, gpointer user_data)
value = (char *)data;
req = (struct request *)user_data;
- vici_list_item(req, value, strlen(value));
+ list_item(req, value, strlen(value));
return;
}
@@ -373,87 +486,515 @@ static void write_section_kvls(VICISection *section, struct request *req)
return;
g_hash_table_iter_init (&iter, section->kvls);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
if (!key || !value)
continue;
- vici_list_start(req, key);
- g_slist_foreach((GSList *)value, (GFunc)_write_vl, (gpointer)req);
- vici_list_end(req);
+ list_start(req, key);
+ g_slist_foreach((GSList *)value, (GFunc)write_list_item, (gpointer)req);
+ list_end(req);
}
return;
}
-static void _write_section(struct request *req, VICISection *section)
+static void write_section(struct request *req, VICISection *section)
{
GHashTableIter iter;
gpointer key, value;
- VICISection *subsection;
if (req == NULL || section == NULL)
return;
if (section->name)
- vici_section_start(req, section->name);
+ section_start(req, section->name);
write_section_kvs(section, req);
write_section_kvls(section, req);
g_hash_table_iter_init(&iter, section->subsection);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
if (!key || !value)
continue;
- subsection = value;
- _write_section(req, subsection);
+ write_section(req, (VICISection *)value);
}
if (section->name)
- vici_section_end(req);
+ section_end(req);
return;
}
-static int vici_client_send_command(struct request *req)
+static int check_socket(int sock)
{
- return 0;
+ struct pollfd p_fd;
+ int res = 0;
+
+ p_fd.fd = sock;
+ p_fd.events = POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL;
+ res = poll((struct pollfd *) &p_fd, 1, 1);
+
+ if (res < 0) {
+ connman_error("Polling error from socket\n");
+ return -1;
+ } else if (res == 0) {
+ connman_error( "poll timeout. socket is busy\n");
+ return 1;
+ } else {
+
+ if (p_fd.revents & POLLERR) {
+ connman_error("Error! POLLERR from socket[%d]\n", sock);
+ return -1;
+ } else if (p_fd.revents & POLLHUP) {
+ connman_error("Error! POLLHUP from socket[%d]\n", sock);
+ return -1;
+ } else if (p_fd.revents & POLLNVAL) {
+ connman_error("Error! POLLNVAL from socket[%d]\n", sock);
+ return -1;
+ } else if (p_fd.revents & POLLIN) {
+ return 0;
+ } else if (p_fd.revents & POLLOUT) {
+ return 0;
+ }
+ }
+
+ connman_error("Unknown poll event [%d]\n", p_fd.revents);
+ return -1;
}
-static int destroy_vici_request(struct request *req)
+static int write_socket(int sock, char *data, int data_len)
{
- return 0;
+ int wbytes = 0;
+ int left_len = data_len;
+ char *ptr = data;
+ int res = 0;
+
+ if (sock < SOCK_FD_MIN || !data || data_len < 0)
+ return -1;
+
+ res = check_socket(sock);
+ if (res < 0)
+ return -1;
+ else if (res > 0)
+ return -2;
+
+ errno = 0;
+ while (left_len) {
+ wbytes = write(sock, ptr, left_len);
+ if (wbytes <= 0) {
+ connman_error("Failed to write data into socket[%d].\n", sock);
+ break;
+ }else if (wbytes < left_len) {
+ left_len -= wbytes;
+ ptr += wbytes;
+ } else if (wbytes == left_len) {
+ left_len = 0;
+ } else {
+ connman_error("Unknown error occurred.\n");
+ break;
+ }
+ }
+
+ if (left_len)
+ return -1;
+ else
+ return 0;
+}
+
+int send_vici_command(struct request *req, VICIClient *vici_client)
+{
+ unsigned int size = 0;
+ int res = 0;
+
+ if (req == NULL) {
+ connman_error("request is NULL\n");
+ return -EINVAL;
+ }
+
+ size = htonl(req->used);
+ res = write_socket(vici_client->client_sock_fd, (char *)&size, sizeof(size));
+ if (res != 0) {
+ connman_error("failed to send size with network byte order\n");
+ return -EIO;
+ }
+
+ res = write_socket(vici_client->client_sock_fd, req->sndbuf, req->used);
+ if (res != 0) {
+ connman_error("failed to send pkt\n");
+ return -EIO;
+ }
+
+ vici_client->request_list = g_slist_append(vici_client->request_list, req);
+ return res;
+}
+
+static void print_vici_element(int elem_type, char *value, int sections)
+{
+ int i = 0;
+
+
+ switch (elem_type) {
+ case VICI_SECTION_START:
+ for (i = 0; i < sections - 1; i++)
+ DBG("\t");
+ DBG("%s = {\n", value);
+ break;
+ case VICI_SECTION_END:
+ for (i = 0; i < sections; i++)
+ DBG("\t");
+ DBG("}\n");
+ break;
+ case VICI_KEY_VALUE:
+ for (i = 0; i < sections; i++)
+ DBG("\t");
+ DBG("%s\n", value);
+ break;
+ case VICI_LIST_START:
+ for (i = 0; i < sections; i++)
+ DBG("\t");
+ DBG("%s = [", value);
+ break;
+ case VICI_LIST_ITEM:
+ DBG("%s, ", value);
+ break;
+ case VICI_LIST_END:
+ DBG("]\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void debug_vici_message(char *buf, unsigned int size)
+{
+ char temp[255];
+ unsigned int pos = 0;
+ int len = 0;
+ int sections = 0;
+ int type = -1;
+
+ if (buf == NULL || size == 0)
+ return;
+
+ pos = 1;
+ while (pos < size) {
+
+ type = buf[pos];
+ pos++;
+ switch (type) {
+ case VICI_SECTION_START:
+ {
+ len = buf[pos];
+ pos++;
+ g_strlcpy(temp, (const gchar *)&buf[pos], len + 1);
+ pos += len;
+ sections++;
+ }
+ break;
+ case VICI_SECTION_END:
+ {
+ sections--;
+ }
+ break;
+ case VICI_KEY_VALUE:
+ {
+ int key_len = 0;
+ int value_len = 0;
+
+ key_len = buf[pos];
+ pos++;
+ g_strlcpy(temp, (const gchar *)&buf[pos], key_len + 1);
+ temp[key_len] = '=';
+ pos += (key_len + 1);
+ value_len = buf[pos];
+ pos++;
+ g_strlcpy(temp + key_len + 1, (const gchar *)&buf[pos], value_len + 1);
+ pos += value_len;
+ len = key_len + 1 + value_len;
+ }
+ break;
+ case VICI_LIST_START:
+ {
+ len = buf[pos];
+ pos++;
+ g_strlcpy(temp, (const gchar *)&buf[pos], len + 1);
+ pos += len;
+ }
+ break;
+ case VICI_LIST_ITEM:
+ {
+ pos++;
+ len = buf[pos];
+ pos++;
+ g_strlcpy(temp, (const gchar *)&buf[pos], len + 1);
+ pos += len;
+ }
+ break;
+ case VICI_LIST_END:
+ break;
+ default:
+ break;
+ }
+ print_vici_element(type, temp, sections);
+ }
+ return;
+}
+
+static unsigned int extract_key_value(char *buf, unsigned int pos, char **key, char **value)
+{
+ int key_len = 0;
+ int value_len = 0;
+
+ key_len = buf[pos];
+ pos++;
+ *key = g_strndup((const gchar *)&buf[pos], key_len);
+ pos+=(key_len + 1);
+ value_len = buf[pos];
+ pos++;
+ *value = g_strndup((const gchar *)&buf[pos], value_len);
+ pos+=value_len;
+ return pos;
+}
+
+static gboolean extract_request_result(char *buf, unsigned int size, char **err)
+{
+ gboolean success = FALSE;
+ unsigned int pos = 0;
+ int type = -1;
+
+ pos = 1;
+ while (pos < size) {
+
+ type = buf[pos];//3
+ pos++;
+ if (type == VICI_KEY_VALUE) {
+ char *key = NULL;
+ char *value = NULL;
+ pos = extract_key_value(buf, pos, &key, &value);
+ DBG("pos : %d size : %d\n", pos, size);
+
+ /* TODO :remove this after debug */
+ DBG("key : %s value : %s\n", key, value);
+ if (g_strcmp0(key, "success") == 0)
+ (g_strcmp0(value, "yes") == 0)?(success = TRUE):(success = FALSE);
+
+ if (g_strcmp0(key, "errmsg"))
+ *err = g_strdup(value);
+ g_free(key);
+ g_free(value);
+ }
+ }
+ return success;
+}
+
+static int handle_vici_result(gboolean success, int cmd, char * err)
+{
+ int ret = 0;
+ if (success)
+ return 0;
+
+ DBG(" %s failed with %s!\n", vici_cmd_str[cmd], err);
+ g_free(err);
+
+ switch (cmd) {
+ case VICI_CMD_LOAD_CONN:
+ ret = EINVAL;
+ break;
+ case VICI_CMD_LOAD_SHARED:
+ ret = EINVAL;
+ break;
+ case VICI_CMD_LOAD_CERT:
+ ret = EINVAL;
+ break;
+ case VICI_CMD_LOAD_AUTH:
+ ret = 0;
+ break;
+ case VICI_CMD_LOAD_KEY:
+ ret = EINVAL;
+ break;
+ case VICI_CMD_INITIATE:
+ ret = ECONNABORTED;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
}
-int vici_client_send_request(const char *cmd, VICISection *root)
+static int process_vici_response(struct request * req)
{
- struct request* req = NULL;
+ char *err = NULL;
+ gboolean success = FALSE;
+ int ret = 0;
+
+ if (!req)
+ return -1;
+
+ if (!req->rcvbuf || req->rcvbuf[0] != VICI_CMD_RESPONSE)
+ return -1;
+
+ //TODO: remove below when there's no further problem.
+ debug_vici_message(req->rcvbuf, req->rcv_pkt_size);
+
+ success = extract_request_result(req->rcvbuf, req->rcv_pkt_size, &err);
+ ret = handle_vici_result(success, req->cmd, err);
+
+ return ret;
+}
+
+int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *root)
+{
+ struct request *req = NULL;
int ret;
+ DBG("%s", vici_cmd_str[cmd]);
ret = create_vici_request(VICI_CMD_REQUEST, cmd, &req);
if (ret < 0) {
connman_error("error on create_request\n");
- return -1;
+ return ret;
}
- _write_section(req, root);
+ write_section(req, root);
+ //TODO: remove below when there's no further problem.
+ debug_vici_message(req->sndbuf + req->hdr_len - 1, req->used - req->hdr_len + 1);
- ret = vici_client_send_command(req);
+ ret = send_vici_command(req, vici_client);
if (ret < 0) {
+ destroy_vici_request(req);
connman_error("error on send_command\n");
+ }
+
+ return ret;
+}
+
+static int get_socket_from_source(GIOChannel *source, GIOCondition condition)
+{
+ int sock = -1;
+ /* check socket */
+ sock = g_io_channel_unix_get_fd(source);
+ if (sock < SOCK_FD_MIN)
+ return -1;
+
+ if ((condition & G_IO_ERR) || (condition & G_IO_HUP) || (condition & G_IO_NVAL)) {
+ connman_error("G_IO_ERR/G_IO_HUP/G_IO_NVAL received sock [%d] condition [%d]\n", sock, condition);
+ //TODO: handle the breaking socket
return -1;
}
+ return sock;
+}
- ret = destroy_vici_request(req);
- if (ret < 0) {
- connman_error("error on destroy_request \n");
+static int read_socket(int sock, char *data, unsigned int data_len)
+{
+ int rbytes = 0;
+ int total_rbytes = 0;
+
+ if (sock < SOCK_FD_MIN || !data || data_len <= 0)
return -1;
+
+ while (data_len > 0) {
+ errno = 0;
+ rbytes = read(sock, data, data_len);
+ if (rbytes <= 0)
+ return -1;
+
+ total_rbytes += rbytes;
+ data += rbytes;
+ data_len -= rbytes;
+ }
+
+ return total_rbytes;
+}
+
+static int recv_vici_pkt(int sock, struct request *req)
+{
+ if(!req)
+ return -1;
+
+ if (req->rcv_pkt_size == 0) {
+ unsigned int pkt_size = 0;
+ if (read_socket(sock, (char *)&pkt_size, sizeof(pkt_size)) < 0)
+ return -1;
+
+ req->rcv_pkt_size = ntohl(pkt_size);
+ /* TODO :REMOVE THIS AFTER DEBUG */
+ DBG("rcv_pkt_size [%d] will be recved\n", req->rcv_pkt_size);
+ } else {
+
+ char *buf = NULL;
+ buf = g_try_malloc0(req->rcv_pkt_size);
+ if (buf == NULL)
+ return -1;
+
+ if (read_socket(sock, buf, req->rcv_pkt_size) < 0) {
+ g_free(buf);
+ return -1;
+ }
+ req->rcvbuf = buf;
}
return 0;
}
-static int str_to_sock_addr(const char *uri, struct sockaddr_un *addr)
+static struct request *pop_vici_request(VICIClient *vici_client)
+{
+ GSList *list = NULL;
+
+ if (!vici_client)
+ return NULL;
+
+ list = vici_client->request_list;
+ if(!list)
+ return NULL;
+
+ return list->data;
+}
+
+static gboolean process_reply(GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ VICIClient *vici_client = NULL;
+ struct request * req = NULL;
+ int sock = 0;
+ int ret = 0;
+
+ vici_client = (VICIClient *)user_data;
+ if (!vici_client)
+ return FALSE;
+
+ sock = get_socket_from_source(source, condition);
+ if (sock < 0)
+ return FALSE;
+
+ /* get first request */
+ req = pop_vici_request((VICIClient *)user_data);
+ if (!req)
+ return FALSE;
+
+ if(recv_vici_pkt(sock, req) < 0)
+ return FALSE;
+
+ if (!req->rcvbuf) {
+ return TRUE;
+ }
+
+ ret = process_vici_response(req);
+ if (ret != 0)
+ vici_client->reply(ret, vici_client->ipsec_user_data);
+
+ vici_client->request_list = g_slist_remove(vici_client->request_list, req);
+ destroy_vici_request(req);
+
+ /* TODO :remove this after debug */
+ DBG("left request reply : %d", g_slist_length(vici_client->request_list));
+ if(g_slist_length(vici_client->request_list) == 0)
+ vici_client->reply(ret, vici_client->ipsec_user_data);
+
+ return TRUE;
+}
+
+static int str_to_socket_addr(const char *uri, struct sockaddr_un *addr)
{
memset(addr, 0, sizeof(*addr));
addr->sun_family = AF_UNIX;
@@ -464,23 +1005,26 @@ static int str_to_sock_addr(const char *uri, struct sockaddr_un *addr)
return offsetof(struct sockaddr_un, sun_path) + strlen(addr->sun_path);
}
-static int connect_sock(const char *uri)
+static int connect_socket(const char *uri)
{
struct sockaddr_un addr;
int len, fd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0)
+ if (fd < 0) {
+ connman_error("socket() failed");
return -errno;
+ }
- len = str_to_sock_addr(uri, &addr);
- if (len == -1)
- {
+ len = str_to_socket_addr(uri, &addr);
+ if (len == -1) {
+ connman_error("str_to_socket_addr failed");
close(fd);
return -1;
}
if (connect(fd, (struct sockaddr*)&addr, len) < 0) {
+ connman_error("connect failed. errno %d/%s", errno, strerror(errno));
close(fd);
return -errno;
}
@@ -488,53 +1032,58 @@ static int connect_sock(const char *uri)
return fd;
}
-static gboolean process_reply(GIOChannel *source, GIOChannel condtion, gpointer user_data)
-{
- return TRUE;
-}
-int vici_client_initialize()
+int vici_initialize(VICIClient **vici_client)
{
GIOChannel *vici_channel;
- VICIClient *vici_client = NULL;
- vici_client = g_try_new0(VICIClient, 1);
- if (!vici_client) {
- return VICI_CLIENT_ERROR_NOMEM;
+ *vici_client = g_try_new0(VICIClient, 1);
+ if (!*vici_client) {
+ connman_error("out of memory");
+ return -ENOMEM;
}
- vici_client->client_sock = connect_sock(VICI_DEFAULT_URI);
- if (vici_client->client_sock < 0) {
- g_free(vici_client);
+ (*vici_client)->client_sock_fd = connect_socket(VICI_DEFAULT_URI);
+ if ((*vici_client)->client_sock_fd < 0) {
+ connman_error("connect_socket failed");
+ g_free(*vici_client);
return -EIO;
}
- vici_channel = g_io_channel_unix_new(vici_client->client_sock);
+ vici_channel = g_io_channel_unix_new((*vici_client)->client_sock_fd);
if (!vici_channel) {
- close(vici_client->client_sock);
- g_free(vici_client);
+ connman_error("g_io_channel_unix_new failed");
+ close((*vici_client)->client_sock_fd);
+ g_free(*vici_client);
+ return -ENOMEM;
}
- vici_client->client_watch = g_io_add_watch_full(vici_channel,
+ (*vici_client)->client_watch = g_io_add_watch_full(vici_channel,
G_PRIORITY_LOW,
G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc)process_reply,
- (gpointer)vici_client,
+ (gpointer)*vici_client,
NULL);
g_io_channel_unref(vici_channel);
+ DBG("connected");
return 0;
}
-int vici_client_deinitialize()
+void vici_set_connect_reply_cb(VICIClient *vici_client, vici_connect_reply_cb reply_cb, gpointer user_data)
{
- VICIClient *vici_client = NULL;
+ vici_client->reply = reply_cb;
+ vici_client->ipsec_user_data = user_data;
+}
+int vici_deinitialize(VICIClient *vici_client)
+{
if (vici_client->client_watch > 0) {
g_source_remove(vici_client->client_watch);
vici_client->client_watch = 0;
}
- close(vici_client->client_sock);
+ close(vici_client->client_sock_fd);
+ g_slist_free_full(vici_client->request_list, destroy_vici_request);
g_free(vici_client);
return 0;
diff --git a/vpn/plugins/vici-client.h b/vpn/plugins/vici-client.h
index a49f0a78..91200e5a 100644
--- a/vpn/plugins/vici-client.h
+++ b/vpn/plugins/vici-client.h
@@ -13,32 +13,41 @@ struct _VICISection;
typedef struct _VICISection VICISection;
typedef enum {
- VICI_CLIENT_ERROR_NONE,
- VICI_CLIENT_ERROR_NOMEM,
-} VICIClientError;
-
-typedef enum {
- VICI_CLIENT_EVENT,
-} VICIClientEvent;
-
-#define VICI_REQUEST_LOAD_CONN "load-conn"
-#define VICI_REQUEST_LOAD_SHARED "load-shared"
-#define VICI_REQUEST_LOAD_CERT "load-cert"
-#define VICI_REQUEST_LOAD_INITIATE "initiate"
-
-typedef int (*vici_section_add_element)(VICISection *sect, const char *key,
+ VICI_CMD_LOAD_CONN,
+ VICI_CMD_LOAD_SHARED,
+ VICI_CMD_LOAD_CERT,
+ VICI_CMD_LOAD_AUTH,
+ VICI_CMD_UNLOAD_AUTH,
+ VICI_CMD_LOAD_KEY,
+ VICI_CMD_INITIATE,
+ VICI_CMD_MAX,
+} VICIClientCmd;
+
+#define VICI_DEFAULT_URI "/var/run/charon.vici"
+
+typedef int (*vici_add_element)(VICISection *sect, const char *key,
const char *value, const char *subsection);
+typedef void (*vici_connect_reply_cb)(int err, void *user_data);
+
VICISection* vici_create_section(const char *name);
-int vici_section_add_kv(VICISection *sect, const char *key,
+int add_subsection(const char* name, VICISection* child, VICISection* section);
+void vici_destroy_section(VICISection *sect);
+int vici_add_kv(VICISection *sect, const char *key,
const char *value, const char *subsection);
-int vici_section_add_kvl(VICISection *sect, const char *key,
+int vici_add_kvl(VICISection *sect, const char *key,
+ const char *value, const char *subsection);
+int vici_add_list(VICISection* section, char *key,
+ GSList *list, const char* subsection);
+int vici_add_cert_kv(VICISection *section, const char *key,
+ const char *value, const char *subsection);
+int vici_add_cert_kvl(VICISection *section, const char *key,
const char *value, const char *subsection);
-void vici_destroy_section(VICISection *sect);
-int vici_client_initialize();
-int vici_client_deinitialize();
-int vici_client_send_request(const char *cmd, VICISection *root);
+int vici_initialize(VICIClient **vici_client);
+int vici_deinitialize(VICIClient *vici_client);
+void vici_set_connect_reply_cb(VICIClient *vici_client, vici_connect_reply_cb reply_cb, gpointer user_data);
+int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *root);
#ifdef __cplusplus
}
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index b438d06e..3e40e4fe 100755
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -307,6 +307,99 @@ static DBusMessage *vpn_notify(struct connman_task *task,
return NULL;
}
+static void vpn_event(struct vpn_provider *provider, int state)
+{
+ struct vpn_data *data;
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
+ int index, err;
+
+ data = vpn_provider_get_data(provider);
+
+ name = vpn_provider_get_driver_name(provider);
+
+ if (!name) {
+ DBG("Cannot find VPN driver for provider %p", provider);
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
+ return;
+ }
+
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+ if (!vpn_driver_data) {
+ DBG("Cannot find VPN driver data for name %s", name);
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
+ return;
+ }
+
+ DBG("provider %p driver %s state %d", provider, name, state);
+
+ switch (state) {
+ case VPN_STATE_CONNECT:
+ case VPN_STATE_READY:
+ if (data->state == VPN_STATE_READY) {
+ /*
+ * This is the restart case, in which case we must
+ * just set the IP address.
+ *
+ * We need to remove first the old address, just
+ * replacing the old address will not work as expected
+ * because the old address will linger in the interface
+ * and not disapper so the clearing is needed here.
+ *
+ * Also the state must change, otherwise the routes
+ * will not be set properly.
+ */
+ vpn_provider_set_state(provider,
+ VPN_PROVIDER_STATE_CONNECT);
+
+ vpn_provider_clear_address(provider, AF_INET);
+ vpn_provider_clear_address(provider, AF_INET6);
+
+ vpn_provider_change_address(provider);
+ vpn_provider_set_state(provider,
+ VPN_PROVIDER_STATE_READY);
+ break;
+ }
+
+ index = vpn_provider_get_index(provider);
+ vpn_provider_ref(provider);
+ data->watch = vpn_rtnl_add_newlink_watch(index,
+ vpn_newlink, provider);
+ err = connman_inet_ifup(index);
+ if (err < 0) {
+ if (err == -EALREADY)
+ /*
+ * So the interface is up already, that is just
+ * great. Unfortunately in this case the
+ * newlink watch might not have been called at
+ * all. We must manually call it here so that
+ * the provider can go to ready state and the
+ * routes are setup properly.
+ */
+ vpn_newlink(IFF_UP, 0, provider);
+ else
+ DBG("Cannot take interface %d up err %d/%s",
+ index, -err, strerror(-err));
+ }
+ break;
+
+ case VPN_STATE_UNKNOWN:
+ case VPN_STATE_IDLE:
+ case VPN_STATE_DISCONNECT:
+ case VPN_STATE_FAILURE:
+ vpn_provider_set_state(provider,
+ VPN_PROVIDER_STATE_DISCONNECT);
+ break;
+
+ case VPN_STATE_AUTH_FAILURE:
+ vpn_provider_indicate_error(provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ break;
+ }
+
+ return;
+}
+
static int vpn_create_tun(struct vpn_provider *provider)
{
struct vpn_data *data = vpn_provider_get_data(provider);
@@ -454,6 +547,10 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
+
+ if(vpn_driver_data->vpn_driver->set_event_cb)
+ vpn_driver_data->vpn_driver->set_event_cb(vpn_event, provider);
+
ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
data->if_name, cb, dbus_sender,
user_data);
diff --git a/vpn/plugins/vpn.h b/vpn/plugins/vpn.h
index bf56728d..61758636 100755
--- a/vpn/plugins/vpn.h
+++ b/vpn/plugins/vpn.h
@@ -40,9 +40,12 @@ enum vpn_state {
VPN_STATE_AUTH_FAILURE = 6,
};
+typedef void (*vpn_event_callback)(struct vpn_provider *provider, int state);
+
struct vpn_driver {
int flags;
int (*notify) (DBusMessage *msg, struct vpn_provider *provider);
+ void (*set_event_cb) (vpn_event_callback event_cb, struct vpn_provider *provider);
int (*connect) (struct vpn_provider *provider,
struct connman_task *task, const char *if_name,
vpn_provider_connect_cb_t cb, const char *dbus_sender,
diff --git a/vpn/vpn-config.c b/vpn/vpn-config.c
index 293c64e0..a5be332d 100755
--- a/vpn/vpn-config.c
+++ b/vpn/vpn-config.c
@@ -203,7 +203,11 @@ static int load_provider(GKeyFile *keyfile, const char *group,
struct vpn_config *config, enum what action)
{
struct vpn_config_provider *config_provider;
+#if !defined TIZEN_EXT
const char *ident, *host, *domain;
+#else
+ const char *ident, *host, *domain, *name;
+#endif
int err;
/* Strip off "provider_" prefix */
@@ -229,8 +233,14 @@ static int load_provider(GKeyFile *keyfile, const char *group,
host = get_string(config_provider, "Host");
domain = get_string(config_provider, "Domain");
+#if !defined TIZEN_EXT
if (host && domain) {
char *id = __vpn_provider_create_identifier(host, domain);
+#else
+ name = get_string(config_provider, "Name");
+ if (host && domain && name) {
+ char *id = __vpn_provider_create_identifier(host, domain, name);
+#endif
struct vpn_provider *provider;
provider = __vpn_provider_lookup(id);
@@ -252,7 +262,11 @@ static int load_provider(GKeyFile *keyfile, const char *group,
DBG("provider identifier %s", id);
} else {
+#if !defined TIZEN_EXT
DBG("invalid values host %s domain %s", host, domain);
+#else
+ DBG("invalid values host %s domain %s name %s", host, domain, name);
+#endif
err = -EINVAL;
goto err;
}
diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index 16c0c2be..925f6997 100755
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -1757,6 +1757,7 @@ static void provider_create_all_from_type(const char *provider_type)
g_strfreev(providers);
}
+#if !defined TIZEN_EXT
char *__vpn_provider_create_identifier(const char *host, const char *domain)
{
char *ident;
@@ -1769,6 +1770,20 @@ char *__vpn_provider_create_identifier(const char *host, const char *domain)
return ident;
}
+#else
+char *__vpn_provider_create_identifier(const char *host, const char *domain, const char *name)
+{
+ char *ident;
+
+ ident = g_strdup_printf("%s_%s_%s", host, domain, name);
+ if (!ident)
+ return NULL;
+
+ provider_dbus_ident(ident);
+
+ return ident;
+}
+#endif
int __vpn_provider_create(DBusMessage *msg)
{
@@ -1822,7 +1837,11 @@ int __vpn_provider_create(DBusMessage *msg)
if (!type || !name)
return -EOPNOTSUPP;
+#if !defined TIZEN_EXT
ident = __vpn_provider_create_identifier(host, domain);
+#else
+ ident = __vpn_provider_create_identifier(host, domain, name);
+#endif
DBG("ident %s", ident);
provider = __vpn_provider_lookup(ident);
@@ -2011,7 +2030,11 @@ int __vpn_provider_create_from_config(GHashTable *settings,
goto fail;
}
+#if !defined TIZEN_EXT
ident = __vpn_provider_create_identifier(host, domain);
+#else
+ ident = __vpn_provider_create_identifier(host, domain, name);
+#endif
DBG("ident %s", ident);
provider = __vpn_provider_lookup(ident);
diff --git a/vpn/vpn.h b/vpn/vpn.h
index 8bf86bd1..26b13d70 100755
--- a/vpn/vpn.h
+++ b/vpn/vpn.h
@@ -71,8 +71,11 @@ int __vpn_ipconfig_init(void);
void __vpn_ipconfig_cleanup(void);
#include "vpn-provider.h"
-
+#if !defined TIZEN_EXT
char *__vpn_provider_create_identifier(const char *host, const char *domain);
+#else
+char *__vpn_provider_create_identifier(const char *host, const char *domain, const char *name);
+#endif
bool __vpn_provider_check_routes(struct vpn_provider *provider);
int __vpn_provider_append_user_route(struct vpn_provider *provider,
int family, const char *network,