5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/log.h>
36 #include <connman/task.h>
37 #include <connman/dbus.h>
38 #include <connman/ipconfig.h>
40 #include "../vpn-provider.h"
44 #include "vici-client.h"
46 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
48 static DBusConnection *connection;
54 } ipsec_conn_options[] = {
55 {"IPsec.Version", "version", NULL},
56 {"IPsec.LocalAddrs", "local_addrs", NULL},
57 {"IPsec.RemoteAddrs", "remote_addrs", NULL},
58 {"IPsec.LocalAuth", "auth", "local"},
59 {"IPsec.RemoteAuth", "auth", "remote"},
68 const char *vici_type;
69 } ipsec_shared_options[] = {
70 {"IPsec.LocalXauthID", NULL},
71 {"IPsec.XauthSecret", "XAUTH"},
72 {"IPsec.IKESecret", "IKE"},
77 const char *vici_type;
78 const char *vici_flag;
79 } ipsec_cert_options[] = {
80 {"IPsec.LocalCert", "X509", NULL},
81 {"IPsec.RemoteCert", "X509", NULL},
82 {"IPsec.CACert", "X509", "CA"},
86 static int ipsec_notify(DBusMessage *msg, struct vpn_provider *provider)
91 static void vici_destroy_section(struct section* sect)
93 g_hash_table_destroy(sect->elm);
94 g_hash_table_destroy(sect->subsection);
98 static void free_section(gpointer data)
100 struct section* sect = (struct section*)data;
101 vici_destroy_section(sect);
104 static struct section* vici_create_section(const char* name)
106 struct section* sect;
108 sect = g_try_new0(struct section, 1);
110 connman_error("Failed to create section");
114 sect->name = g_strdup(name);
115 sect->elm = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
116 sect->subsection = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_section);
120 static int vici_section_add_kv(struct section* sect, const char* key, const char* value)
122 if (sect == NULL || key == NULL || value == NULL) {
123 connman_error("invalid parameter");
127 g_hash_table_insert(sect->elm, g_strdup(key), g_strdup(value));
131 static int vici_section_add_subsection(struct section* sect, const char* name, struct section* child)
133 if (sect == NULL || name == NULL || child == NULL) {
134 connman_error("invalid parameter");
138 g_hash_table_insert(sect->subsection, g_strdup(name), child);
143 static struct section* vici_section_get_subsection(struct section* sect, const char* name)
145 struct section* sub = g_hash_table_lookup(sect->subsection, name);
147 sub = vici_create_section(name);
148 vici_section_add_subsection(sect, name, sub);
153 static int vici_section_add_element(struct section* sect, const char* key,
154 const char* value, const char* subsection)
156 struct section* target = sect;
158 if (sect == NULL || key == NULL) {
159 connman_error("invalid parameter");
164 target = vici_section_get_subsection(sect, subsection);
166 vici_section_add_kv(target, key, value);
170 static int ipsec_is_same_auth(const char* req, const char* target)
172 if (req == NULL || target == NULL)
174 return (g_strcmp0(req, target) == 0);
177 static int vici_load_cert(const char* type, const char* flag, const char* data)
179 struct section *sect;
180 sect = vici_create_section("");
181 vici_section_add_element(sect, "type", type, NULL);
182 vici_section_add_element(sect, "flag", flag, NULL);
183 vici_section_add_element(sect, "data", data, NULL);
185 vici_client_send_request(VICI_REQUEST_LOAD_CERT, sect);
187 vici_destroy_section(sect);
192 static int ipsec_load_conn(struct vpn_provider *provider)
196 const char *subsection;
197 struct section *sect;
200 value = vpn_provider_get_string(provider, "Name");
201 sect = vici_create_section(value);
203 for (i = 0; i < (int)ARRAY_SIZE(ipsec_conn_options); i++) {
204 key = ipsec_conn_options[i].vici_key;
205 value = vpn_provider_get_string(provider, ipsec_conn_options[i].cm_opt);
206 subsection = ipsec_conn_options[i].section;
207 vici_section_add_element(sect, key, value, subsection);
210 vici_client_send_request(VICI_REQUEST_LOAD_CONN, sect);
212 vici_destroy_section(sect);
217 static int ipsec_load_shared(struct vpn_provider *provider)
222 const char *auth_type;
223 struct section *sect;
225 sect = vici_create_section("");
227 auth_type = vpn_provider_get_string(provider, "IPsec.LocalAuth");
228 if (ipsec_is_same_auth(auth_type, IPSEC_AUTH_PSK)) {
229 type = VICI_SHARED_TYPE_PSK;
230 data = vpn_provider_get_string(provider, "IPsec.IKESecret");
231 } else if (ipsec_is_same_auth(auth_type, IPSEC_AUTH_XAUTH)) {
232 type = VICI_SHARED_TYPE_XAUTH;
233 data = vpn_provider_get_string(provider, "IPsec.XauthSecret");
235 connman_error("invalid auth type: %s", auth_type);
239 owner = vpn_provider_get_string(provider, "IPsec.LocalXauthID");
241 vici_section_add_element(sect, "type", type, NULL);
242 vici_section_add_element(sect, "data", data, NULL);
243 vici_section_add_element(sect, "owner", owner, NULL);
245 vici_client_send_request(VICI_REQUEST_LOAD_SHARED, sect);
247 vici_destroy_section(sect);
252 static int ipsec_load_cert(struct vpn_provider *provider)
257 const char *auth_type;
260 auth_type = vpn_provider_get_string(provider, "IPsec.LocalAuth");
261 if (!ipsec_is_same_auth(auth_type, IPSEC_AUTH_RSA)) {
262 connman_error("invalid auth type: %s", auth_type);
266 for (i = 0; i < (int)ARRAY_SIZE(ipsec_cert_options); i++) {
267 type = ipsec_cert_options[i].vici_type;;
268 flag = ipsec_cert_options[i].vici_flag;
269 data = vpn_provider_get_string(provider, ipsec_cert_options[i].cm_opt);
270 vici_load_cert(type, flag, data);
276 static int ipsec_connect(struct vpn_provider *provider,
277 struct connman_task *task, const char *if_name,
278 vpn_provider_connect_cb_t cb, const char *dbus_sender,
284 * Start charon daemon using ipsec script of strongSwan.
286 connman_task_add_argument(task, "start", NULL);
287 err = connman_task_run(task, vpn_died, provider, NULL, NULL, NULL);
288 IPSEC_ERROR_CHECK_GOTO(err, done, "ipsec start failed");
291 * Initialize vici client
293 err = vici_client_initialize();
294 IPSEC_ERROR_CHECK_GOTO(err, done, "failed to initialize vici_client");
297 * Send the load-conn command
299 err = ipsec_load_conn(provider);
300 IPSEC_ERROR_CHECK_GOTO(err, done, "load-conn failed");
303 * Send the load-shared command for PSK or XAUTH
305 err = ipsec_load_shared(provider);
306 IPSEC_ERROR_CHECK_GOTO(err, done, "load-shared failed");
309 * Send the load-cert command
311 err = ipsec_load_cert(provider);
312 IPSEC_ERROR_CHECK_GOTO(err, done, "load-cert failed");
316 cb(provider, user_data, err);
321 static int ipsec_error_code(struct vpn_provider *provider, int exit_code)
326 static int ipsec_save(struct vpn_provider *provider, GKeyFile *keyfile)
331 static void ipsec_disconnect(struct vpn_provider *provider)
335 err = vici_client_deinitialize();
336 IPSEC_ERROR_CHECK_RETURN(err, "failed to deinitialize vici_client");
339 static struct vpn_driver vpn_driver = {
340 .flags = VPN_FLAG_NO_TUN,
341 .notify = ipsec_notify,
342 .connect = ipsec_connect,
343 .error_code = ipsec_error_code,
345 .disconnect = ipsec_disconnect,
348 static int ipsec_init(void)
350 connection = connman_dbus_get_connection();
352 return vpn_register("ipsec", &vpn_driver, IPSEC);
355 static void ipsec_exit(void)
357 vpn_unregister("ipsec");
359 dbus_connection_unref(connection);
362 CONNMAN_PLUGIN_DEFINE(ipsec, "IPSec plugin", VERSION,
363 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ipsec_init, ipsec_exit)