struct ipsec_private_data {
struct vpn_provider *provider;
struct openssl_private_data openssl_data;
- vpn_provider_connect_cb_t cb;
+ vpn_provider_connect_cb_t connect_cb;
+ void *connect_user_data;
+};
- void *user_data;
+struct ipsec_event_data {
+ vpn_event_callback event_cb;
+ void *event_user_data;
};
struct {
NULL,
};
-static const char *ikev2_esp_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024";
+static const char *ikev2_esp_proposals = "aes256-aes128-sha256-sha1";
static const char *ikev2_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024";
+static struct ipsec_event_data event_data;
+
static void init_openssl(void)
{
/* Load the human readable error strings for libcrypto */
return cert_type;
}
-static void read_der_file(const char *path, X509 **cert)
+static int read_der_file(const char *path, X509 **cert)
{
FILE *fp = NULL;
+ int err = 0;
+
+ if(!path || !cert) {
+ /* TODO :remove this after debug */
+ DBG("there's no cert data");
+ return 0;
+ }
DBG("der path %s\n", path);
fp = fopen(path, "r");
+ if (!fp) {
+ connman_error("Failed to open file");
+ return -EINVAL;
+ }
+
*cert = d2i_X509_fp(fp, NULL);
+ if (!fp) {
+ connman_error("Failed to read der file");
+ err = -EINVAL;
+ }
+
fclose(fp);
- return;
+ return err;
}
-static void read_pem_file(const char *path, X509 **cert)
+static int read_pem_file(const char *path, X509 **cert)
{
FILE *fp = NULL;
+ int err = 0;
+
+ if(!path || !cert) {
+ /* TODO :remove this after debug */
+ DBG("there's no cert data");
+ return 0;
+ }
DBG("pem path %s\n", path);
fp = fopen(path, "r");
+ if (!fp) {
+ connman_error("Failed to open file");
+ return -EINVAL;
+ }
+
*cert = PEM_read_X509(fp, cert, NULL, NULL);
+ if (!fp) {
+ connman_error("Failed to read pem file");
+ err = -EINVAL;
+ }
+
fclose(fp);
- return;
+ return err;
}
-static void read_pkcs12_file(const char *path, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca)
+static int read_pkcs12_file(const char *path, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca)
{
FILE *fp = NULL;
PKCS12 *p12;
+ int err = 0;
+
+ if(!path || !pass || !pkey || !cert || !ca) {
+ /* TODO :remove this after debug */
+ DBG("there's no cert data");
+ return 0;
+ }
DBG("pkcs12 path %s\n", path);
fp = fopen(path, "r");
+ if (!fp) {
+ connman_error("Failed to open file");
+ return -EINVAL;
+ }
p12 = d2i_PKCS12_fp(fp, NULL);
if (!p12) {
- print_openssl_error();
+ connman_error("Failed to open pkcs12");
fclose(fp);
- return;
+ return -EINVAL;
}
if (!PKCS12_parse(p12, pass, pkey, cert, ca)) {
- print_openssl_error();
- fclose(fp);
- return;
+ connman_error("Failed to parse pkcs12");
+ err = -EINVAL;
}
PKCS12_free(p12);
- return;
+ fclose(fp);
+
+ return err;
}
static char *get_private_key_str(struct openssl_private_data *data)
return get_cert_str(cert);
}
-static void extract_cert_info(const char *path, const char *pass, struct openssl_private_data *data)
+static int extract_cert_info(const char *path, const char *pass, struct openssl_private_data *data)
{
+ int err = 0;
if(!path || !data) {
/* TODO :remove this after debug */
DBG("there's no cert data");
- return;
+ return 0;
}
switch (get_cert_type(path)) {
case CERT_TYPE_DER:
- read_der_file(path, &(data->local_cert));
+ err = read_der_file(path, &(data->local_cert));
break;
case CERT_TYPE_PEM:
- read_pem_file(path, &(data->local_cert));
+ err = 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));
+ err = read_pkcs12_file(path, pass, &(data->private_key), &(data->local_cert), &(data->ca_certs));
break;
default:
break;
}
- return;
+ return err;
}
static void free_openssl_private_data(struct openssl_private_data *data)
return 0;
}
+static void ipsec_set_event_cb(vpn_event_callback event_cb, struct vpn_provider *provider)
+{
+ DBG("set event cb!");
+ event_data.event_cb = event_cb;
+ event_data.event_user_data = provider;
+ return;
+}
+
static int ipsec_is_same_auth(const char* req, const char* target)
{
if (req == NULL || target == NULL)
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");
+ g_slist_free_full(list, g_free);
list = NULL;
} else {
vici_add_kvl(child, "esp_proposals", ikev2_esp_proposals, "net");
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);
+ g_slist_free_full(list, g_free);
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);
}
size_t file_size = 0;
char *file_buff = NULL;
- if (path) {
+ if (!path) {
connman_error("File path is NULL\n");
return NULL;
}
DBG("CertType: %s, CertFalg: %s,CertData: %s", type, flag, data);
if (!type || ! flag || !data) {
connman_error("invalid certification information");
+ g_free(data);
return -EINVAL;
}
return ret;
}
-void connect_reply_cb(int err, void *user_data)
+static int ipsec_terminate(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);
+ vici_add_kv(sect, "ike", vpn_provider_get_string(provider, "Name"), NULL);
+ vici_add_kv(sect, "timeout", "-1", NULL);
+ ret = vici_send_request(vici_client, VICI_CMD_TERMINATE, sect);
+ if (ret < 0)
+ connman_error("vici_send_request failed");
+
+ vici_destroy_section(sect);
+
+ return ret;
+}
+
+static void request_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);
+ DBG("request reply cb");
+
+ if(err != 0) {
+ if (event_data.event_cb)
+ event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE);
+ /* TODO: Does close socket needed? */
+ } else {
+ DBG("Series of requests are succeeded");
+ /* TODO: Not sure about below */
+ if (event_data.event_cb)
+ event_data.event_cb(event_data.event_user_data, VPN_STATE_CONNECT);
+ }
free_private_data(data);
}
+static void ipsec_vici_event_cb(VICIClientEvent event, void *user_data)
+{
+ struct vpn_provider *provider;
+
+ provider = (struct vpn_provider *)user_data;
+ if (!provider) {
+ DBG("Invalid user data");
+ return;
+ }
+
+ if(event == VICI_EVENT_CHILD_UP) {
+ if (event_data.event_cb)
+ event_data.event_cb(event_data.event_user_data, VPN_STATE_READY);
+ } else if (event == VICI_EVENT_CHILD_DOWN) {
+ if (event_data.event_cb)
+ event_data.event_cb(event_data.event_user_data, VPN_STATE_DISCONNECT);
+ } else {
+ DBG("Unknown event");
+ }
+
+ return;
+}
+
static struct ipsec_private_data* create_ipsec_private_data(struct vpn_provider *provider,
vpn_provider_connect_cb_t cb, void* user_data)
{
init_openssl();
data->provider = provider;
- data->cb = cb;
- data->user_data = user_data;
+ data->connect_cb = cb;
+ data->connect_user_data = user_data;
return data;
}
IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid data parameter");
provider = data->provider;
- cb = data->cb;
+ cb = data->connect_cb;
if (!provider || !cb)
IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid provider or callback");
/* 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);
+ vici_set_request_reply_cb(vici_client, (vici_request_reply_cb)request_reply_cb, data);
+ /*
+ * Sets child-updown event
+ */
+ err = vici_set_event_cb(vici_client, (vici_event_cb)ipsec_vici_event_cb, provider);
+ IPSEC_ERROR_CHECK_GOTO(err, done, "register event failed");
+ /* TODO :remove this after debug */
+ DBG("success to vici_set_event_cb");
/*
* Send the load-conn command
*/
done:
/* refer to connect_cb on vpn-provider.c for cb */
- if(err != 0 && cb)
- cb(provider, data->user_data, -err);
+ if(cb)
+ cb(provider, data->connect_user_data, -err);
+ /* TODO: Does close socket needed? when err is not zero */
return;
}
if (error) {
connman_error("g_file_monitor_directory failed: %s / %d", error->message, error->code);
g_error_free(error);
+ if(event_data.event_cb)
+ event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE);
return;
}
/* TODO :remove this after debug */
}
}
+static void ipsec_died(struct connman_task *task, int exit_code, void *user_data)
+{
+ DBG("task %p exit_code %d", task, exit_code);
+ unlink(VICI_DEFAULT_URI);
+ vpn_died(task, exit_code, user_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,
/*
* Start charon daemon using ipsec script of strongSwan.
*/
- err = connman_task_run(task, vpn_died, provider, NULL, NULL, NULL);
+ err = connman_task_run(task, ipsec_died, provider, NULL, NULL, NULL);
if (err < 0) {
connman_error("charon start failed");
if (cb)
cb(provider, user_data, err);
+
+ g_free(data);
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));
+ err = extract_cert_info(path, pass, &(data->openssl_data));
+ if (err < 0) {
+ connman_error("extract cert info failed");
+ if (cb)
+ cb(provider, user_data, err);
+
+ g_free(data);
+ return err;
+ }
check_vici_socket(data);
// g_usleep(G_USEC_PER_SEC);
static void ipsec_disconnect(struct vpn_provider *provider)
{
int err = 0;
+ /*
+ * Send the terminate command
+ */
+ err = ipsec_terminate(provider);
+ IPSEC_ERROR_CHECK_RETURN(err, "terminate failed");
err = vici_deinitialize(vici_client);
IPSEC_ERROR_CHECK_RETURN(err, "failed to deinitialize vici_client");
+
+ return;
}
static struct vpn_driver vpn_driver = {
.flags = VPN_FLAG_NO_TUN,
.notify = ipsec_notify,
+ .set_event_cb = ipsec_set_event_cb,
.connect = ipsec_connect,
.error_code = ipsec_error_code,
.save = ipsec_save,
{
connection = connman_dbus_get_connection();
+ event_data.event_cb = NULL;
+ event_data.event_user_data = NULL;
+
return vpn_register("ipsec", &vpn_driver, IPSEC);
}