5 * Copyright (C) 2010-2014 BMW Car IT GmbH.
6 * Copyright (C) 2016-2019 Jolla Ltd.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <linux/if_tun.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
40 #define CONNMAN_API_SUBJECT_TO_CHANGE
41 #include <connman/plugin.h>
42 #include <connman/log.h>
43 #include <connman/task.h>
44 #include <connman/dbus.h>
45 #include <connman/ipconfig.h>
46 #include <connman/agent.h>
47 #include <connman/setting.h>
48 #include <connman/vpn-dbus.h>
50 #include "../vpn-provider.h"
51 #include "../vpn-agent.h"
55 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
57 static DBusConnection *connection;
64 { "Host", "--remote", 1 },
65 { "OpenVPN.CACert", "--ca", 1 },
66 { "OpenVPN.Cert", "--cert", 1 },
67 { "OpenVPN.Key", "--key", 1 },
68 { "OpenVPN.MTU", "--tun-mtu", 1 },
69 { "OpenVPN.NSCertType", "--ns-cert-type", 1 },
70 { "OpenVPN.Proto", "--proto", 1 },
71 { "OpenVPN.Port", "--port", 1 },
72 { "OpenVPN.AuthUserPass", "--auth-user-pass", 1 },
73 { "OpenVPN.AskPass", "--askpass", 1 },
74 { "OpenVPN.AuthNoCache", "--auth-nocache", 0 },
75 { "OpenVPN.TLSRemote", "--tls-remote", 1 },
76 { "OpenVPN.TLSAuth", NULL, 1 },
77 { "OpenVPN.TLSAuthDir", NULL, 1 },
78 { "OpenVPN.TLSCipher", "--tls-cipher", 1},
79 { "OpenVPN.Cipher", "--cipher", 1 },
80 { "OpenVPN.Auth", "--auth", 1 },
81 { "OpenVPN.CompLZO", "--comp-lzo", 0 },
82 { "OpenVPN.RemoteCertTls", "--remote-cert-tls", 1 },
83 { "OpenVPN.ConfigFile", "--config", 1 },
84 { "OpenVPN.DeviceType", NULL, 1 },
85 { "OpenVPN.Verb", "--verb", 1 },
86 { "OpenVPN.Ping", "--ping", 1},
87 { "OpenVPN.PingExit", "--ping-exit", 1},
88 { "OpenVPN.RemapUsr1", "--remap-usr1", 1},
91 struct ov_private_data {
92 struct vpn_provider *provider;
93 struct connman_task *task;
96 vpn_provider_connect_cb_t cb;
101 GIOChannel *mgmt_channel;
102 int connect_attempts;
103 int failed_attempts_privatekey;
106 static void ov_connect_done(struct ov_private_data *data, int err)
108 if (data && data->cb) {
109 vpn_provider_connect_cb_t cb = data->cb;
110 void *user_data = data->user_data;
112 /* Make sure we don't invoke this callback twice */
114 data->user_data = NULL;
115 cb(data->provider, user_data, err);
119 data->failed_attempts_privatekey = 0;
122 static void free_private_data(struct ov_private_data *data)
124 if (vpn_provider_get_plugin_data(data->provider) == data)
125 vpn_provider_set_plugin_data(data->provider, NULL);
127 ov_connect_done(data, EIO);
128 vpn_provider_unref(data->provider);
129 g_free(data->dbus_sender);
130 g_free(data->if_name);
131 g_free(data->mgmt_path);
135 struct nameserver_entry {
140 static struct nameserver_entry *ov_append_dns_entries(const char *key,
143 struct nameserver_entry *entry = NULL;
146 if (!g_str_has_prefix(key, "foreign_option_"))
149 options = g_strsplit(value, " ", 3);
151 !strcmp(options[0], "dhcp-option") &&
153 !strcmp(options[1], "DNS") &&
156 entry = g_try_new(struct nameserver_entry, 1);
157 #if defined TIZEN_EXT
167 entry->nameserver = g_strdup(options[2]);
168 entry->id = atoi(key + 15); /* foreign_option_XXX */
176 static char *ov_get_domain_name(const char *key, const char *value)
181 if (!g_str_has_prefix(key, "foreign_option_"))
184 options = g_strsplit(value, " ", 3);
186 !strcmp(options[0], "dhcp-option") &&
188 !strcmp(options[1], "DOMAIN") &&
191 domain = g_strdup(options[2]);
199 static gint cmp_ns(gconstpointer a, gconstpointer b)
201 struct nameserver_entry *entry_a = (struct nameserver_entry *)a;
202 struct nameserver_entry *entry_b = (struct nameserver_entry *)b;
204 if (entry_a->id < entry_b->id)
207 if (entry_a->id > entry_b->id)
213 static void free_ns_entry(gpointer data)
215 struct nameserver_entry *entry = data;
217 g_free(entry->nameserver);
221 static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
223 DBusMessageIter iter, dict;
224 const char *reason, *key, *value;
225 char *address = NULL, *gateway = NULL, *peer = NULL, *netmask = NULL;
226 struct connman_ipaddress *ipaddress;
227 GSList *nameserver_list = NULL;
228 struct ov_private_data *data = vpn_provider_get_plugin_data(provider);
230 dbus_message_iter_init(msg, &iter);
232 dbus_message_iter_get_basic(&iter, &reason);
233 dbus_message_iter_next(&iter);
236 connman_error("No provider found");
237 return VPN_STATE_FAILURE;
240 DBG("%p %s", vpn_provider_get_name(provider), reason);
242 if (strcmp(reason, "up")) {
243 ov_connect_done(data, EIO);
244 return VPN_STATE_DISCONNECT;
247 dbus_message_iter_recurse(&iter, &dict);
249 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
250 struct nameserver_entry *ns_entry = NULL;
251 DBusMessageIter entry;
253 dbus_message_iter_recurse(&dict, &entry);
254 dbus_message_iter_get_basic(&entry, &key);
255 dbus_message_iter_next(&entry);
256 dbus_message_iter_get_basic(&entry, &value);
258 DBG("%s = %s", key, value);
260 if (!strcmp(key, "trusted_ip"))
261 gateway = g_strdup(value);
263 if (!strcmp(key, "ifconfig_local"))
264 address = g_strdup(value);
266 if (!strcmp(key, "ifconfig_netmask"))
267 netmask = g_strdup(value);
269 if (!strcmp(key, "ifconfig_remote"))
270 peer = g_strdup(value);
272 if (g_str_has_prefix(key, "route_"))
273 vpn_provider_append_route(provider, key, value);
275 if ((ns_entry = ov_append_dns_entries(key, value)))
276 nameserver_list = g_slist_prepend(nameserver_list,
279 char *domain = ov_get_domain_name(key, value);
281 vpn_provider_set_domain(provider, domain);
286 dbus_message_iter_next(&dict);
289 ipaddress = connman_ipaddress_alloc(AF_INET);
291 g_slist_free_full(nameserver_list, free_ns_entry);
297 return VPN_STATE_FAILURE;
300 connman_ipaddress_set_ipv4(ipaddress, address, netmask, gateway);
301 connman_ipaddress_set_peer(ipaddress, peer);
302 connman_ipaddress_set_p2p(ipaddress, true);
303 vpn_provider_set_ipaddress(provider, ipaddress);
305 if (nameserver_list) {
306 char *nameservers = NULL;
309 nameserver_list = g_slist_sort(nameserver_list, cmp_ns);
310 for (tmp = nameserver_list; tmp;
311 tmp = g_slist_next(tmp)) {
312 struct nameserver_entry *ns = tmp->data;
315 nameservers = g_strdup(ns->nameserver);
318 str = g_strjoin(" ", nameservers,
319 ns->nameserver, NULL);
325 g_slist_free_full(nameserver_list, free_ns_entry);
327 vpn_provider_set_nameservers(provider, nameservers);
336 connman_ipaddress_free(ipaddress);
338 ov_connect_done(data, 0);
339 return VPN_STATE_CONNECT;
342 static int ov_save(struct vpn_provider *provider, GKeyFile *keyfile)
347 for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
348 if (strncmp(ov_options[i].cm_opt, "OpenVPN.", 8) == 0) {
349 option = vpn_provider_get_string(provider,
350 ov_options[i].cm_opt);
354 g_key_file_set_string(keyfile,
355 vpn_provider_get_save_group(provider),
356 ov_options[i].cm_opt, option);
362 static int task_append_config_data(struct vpn_provider *provider,
363 struct connman_task *task)
368 for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
369 if (!ov_options[i].ov_opt)
372 option = vpn_provider_get_string(provider,
373 ov_options[i].cm_opt);
378 * If the AuthUserPass option is "-", provide the input
379 * via management interface
381 if (!strcmp(ov_options[i].cm_opt, "OpenVPN.AuthUserPass") &&
382 !strcmp(option, "-"))
385 if (connman_task_add_argument(task,
386 ov_options[i].ov_opt,
387 ov_options[i].has_value ? option : NULL) < 0)
395 static void close_management_interface(struct ov_private_data *data)
397 if (data->mgmt_path) {
398 if (unlink(data->mgmt_path) && errno != ENOENT)
399 connman_warn("Unable to unlink management socket %s: "
400 "%d", data->mgmt_path, errno);
402 g_free(data->mgmt_path);
403 data->mgmt_path = NULL;
406 if (data->mgmt_timer_id != 0) {
407 g_source_remove(data->mgmt_timer_id);
408 data->mgmt_timer_id = 0;
411 if (data->mgmt_event_id) {
412 g_source_remove(data->mgmt_event_id);
413 data->mgmt_event_id = 0;
416 if (data->mgmt_channel) {
417 g_io_channel_shutdown(data->mgmt_channel, FALSE, NULL);
418 g_io_channel_unref(data->mgmt_channel);
419 data->mgmt_channel = NULL;
423 static void ov_died(struct connman_task *task, int exit_code, void *user_data)
425 struct ov_private_data *data = user_data;
427 /* Cancel any pending agent requests */
428 connman_agent_cancel(data->provider);
430 close_management_interface(data);
432 vpn_died(task, exit_code, data->provider);
434 free_private_data(data);
437 static int run_connect(struct ov_private_data *data,
438 vpn_provider_connect_cb_t cb, void *user_data)
440 struct vpn_provider *provider = data->provider;
441 struct connman_task *task = data->task;
445 option = vpn_provider_get_string(provider, "OpenVPN.ConfigFile");
448 * Set some default options if user has no config file.
450 option = vpn_provider_get_string(provider, "OpenVPN.TLSAuth");
452 connman_task_add_argument(task, "--tls-auth", option);
453 option = vpn_provider_get_string(provider,
454 "OpenVPN.TLSAuthDir");
456 connman_task_add_argument(task, option, NULL);
459 connman_task_add_argument(task, "--nobind", NULL);
460 connman_task_add_argument(task, "--persist-key", NULL);
461 connman_task_add_argument(task, "--client", NULL);
464 if (data->mgmt_path) {
465 connman_task_add_argument(task, "--management", NULL);
466 connman_task_add_argument(task, data->mgmt_path, NULL);
467 connman_task_add_argument(task, "unix", NULL);
468 connman_task_add_argument(task, "--management-query-passwords",
470 connman_task_add_argument(task, "--auth-retry", "interact");
473 connman_task_add_argument(task, "--syslog", NULL);
475 connman_task_add_argument(task, "--script-security", "2");
477 connman_task_add_argument(task, "--up",
478 SCRIPTDIR "/openvpn-script");
479 connman_task_add_argument(task, "--up-restart", NULL);
481 connman_task_add_argument(task, "--setenv", NULL);
482 connman_task_add_argument(task, "CONNMAN_BUSNAME",
483 dbus_bus_get_unique_name(connection));
485 connman_task_add_argument(task, "--setenv", NULL);
486 connman_task_add_argument(task, "CONNMAN_INTERFACE",
487 CONNMAN_TASK_INTERFACE);
489 connman_task_add_argument(task, "--setenv", NULL);
490 connman_task_add_argument(task, "CONNMAN_PATH",
491 connman_task_get_path(task));
493 connman_task_add_argument(task, "--dev", data->if_name);
494 option = vpn_provider_get_string(provider, "OpenVPN.DeviceType");
496 connman_task_add_argument(task, "--dev-type", option);
499 * Default to tun for backwards compatibility.
501 connman_task_add_argument(task, "--dev-type", "tun");
504 connman_task_add_argument(task, "--persist-tun", NULL);
506 #if !defined TIZEN_EXT
507 connman_task_add_argument(task, "--route-noexec", NULL);
508 connman_task_add_argument(task, "--ifconfig-noexec", NULL);
512 * Disable client restarts with TCP because we can't handle this at
513 * the moment. The problem is that when OpenVPN decides to switch
514 * from CONNECTED state to RECONNECTING and then to RESOLVE,
515 * it is not possible to do a DNS lookup. The DNS server is
516 * not accessible through the tunnel anymore and so we end up
517 * trying to resolve the OpenVPN servers address.
519 * Disable connetion retrying when OpenVPN is connected over TCP.
520 * With TCP OpenVPN attempts to handle reconnection silently without
521 * reporting the error back when establishing a connection or
522 * reconnecting as succesful one. The latter causes trouble if the
523 * retries are not limited to 1 (no retry) as the interface is up and
524 * connman regards it as the default route and network ceases to work,
527 option = vpn_provider_get_string(provider, "OpenVPN.Proto");
528 if (option && g_str_has_prefix(option, "tcp")) {
529 option = vpn_provider_get_string(provider, "OpenVPN.PingExit");
531 connman_task_add_argument(task, "--ping-restart", "0");
533 connman_task_add_argument(task, "--connect-retry-max", "1");
534 /* Apply defaults for --ping and --ping-exit only with UDP protocol. */
536 /* Apply default of 10 second interval for ping if omitted. */
537 option = vpn_provider_get_string(provider, "OpenVPN.Ping");
539 connman_task_add_argument(task, "--ping", "10");
541 /* Apply default of 60 seconds for ping exit if omitted. */
542 option = vpn_provider_get_string(provider, "OpenVPN.PingExit");
544 connman_task_add_argument(task, "--ping-exit", "60");
547 err = connman_task_run(task, ov_died, data, NULL, NULL, NULL);
550 data->user_data = NULL;
551 connman_error("openvpn failed to start");
554 /* This lets the caller know that the actual result of
555 * the operation will be reported to the callback */
560 static void ov_quote_credential(GString *line, const char *cred)
565 g_string_append_c(line, '"');
567 while (*cred != '\0') {
573 g_string_append_c(line, '\\');
579 g_string_append_c(line, *cred++);
582 g_string_append_c(line, '"');
585 static void ov_return_credentials(struct ov_private_data *data,
586 const char *username, const char *password)
588 GString *reply_string;
592 reply_string = g_string_new(NULL);
594 g_string_append(reply_string, "username \"Auth\" ");
595 ov_quote_credential(reply_string, username);
596 g_string_append_c(reply_string, '\n');
598 g_string_append(reply_string, "password \"Auth\" ");
599 ov_quote_credential(reply_string, password);
600 g_string_append_c(reply_string, '\n');
602 len = reply_string->len;
603 reply = g_string_free(reply_string, FALSE);
605 g_io_channel_write_chars(data->mgmt_channel, reply, len, NULL, NULL);
606 g_io_channel_flush(data->mgmt_channel, NULL);
608 memset(reply, 0, len);
612 static void ov_return_private_key_password(struct ov_private_data *data,
613 const char *privatekeypass)
615 GString *reply_string;
619 reply_string = g_string_new(NULL);
621 g_string_append(reply_string, "password \"Private Key\" ");
622 ov_quote_credential(reply_string, privatekeypass);
623 g_string_append_c(reply_string, '\n');
625 len = reply_string->len;
626 reply = g_string_free(reply_string, FALSE);
628 g_io_channel_write_chars(data->mgmt_channel, reply, len, NULL, NULL);
629 g_io_channel_flush(data->mgmt_channel, NULL);
631 memset(reply, 0, len);
635 static void request_input_append_informational(DBusMessageIter *iter,
638 char *str = "string";
640 connman_dbus_dict_append_basic(iter, "Type",
641 DBUS_TYPE_STRING, &str);
642 str = "informational";
643 connman_dbus_dict_append_basic(iter, "Requirement",
644 DBUS_TYPE_STRING, &str);
647 static void request_input_append_mandatory(DBusMessageIter *iter,
650 char *str = "string";
652 connman_dbus_dict_append_basic(iter, "Type",
653 DBUS_TYPE_STRING, &str);
655 connman_dbus_dict_append_basic(iter, "Requirement",
656 DBUS_TYPE_STRING, &str);
659 static void request_input_append_password(DBusMessageIter *iter,
662 char *str = "password";
664 connman_dbus_dict_append_basic(iter, "Type",
665 DBUS_TYPE_STRING, &str);
667 connman_dbus_dict_append_basic(iter, "Requirement",
668 DBUS_TYPE_STRING, &str);
671 static void request_input_credentials_reply(DBusMessage *reply,
674 struct ov_private_data *data = user_data;
675 char *username = NULL;
676 char *password = NULL;
678 DBusMessageIter iter, dict;
682 connman_info("provider %p", data->provider);
685 * When connmand calls disconnect because of connection timeout no
693 dbus_error_init(&error);
695 err = vpn_agent_check_and_process_reply_error(reply, data->provider,
696 data->task, data->cb, data->user_data);
698 /* Ensure cb is called only once */
700 data->user_data = NULL;
704 if (!vpn_agent_check_reply_has_dict(reply)) {
709 dbus_message_iter_init(reply, &iter);
710 dbus_message_iter_recurse(&iter, &dict);
711 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
712 DBusMessageIter entry, value;
714 dbus_message_iter_recurse(&dict, &entry);
715 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
718 dbus_message_iter_get_basic(&entry, &key);
720 if (g_str_equal(key, "OpenVPN.Password")) {
721 dbus_message_iter_next(&entry);
722 if (dbus_message_iter_get_arg_type(&entry)
723 != DBUS_TYPE_VARIANT)
725 dbus_message_iter_recurse(&entry, &value);
726 if (dbus_message_iter_get_arg_type(&value)
729 dbus_message_iter_get_basic(&value, &password);
730 vpn_provider_set_string_hide_value(data->provider,
733 } else if (g_str_equal(key, "OpenVPN.Username")) {
734 dbus_message_iter_next(&entry);
735 if (dbus_message_iter_get_arg_type(&entry)
736 != DBUS_TYPE_VARIANT)
738 dbus_message_iter_recurse(&entry, &value);
739 if (dbus_message_iter_get_arg_type(&value)
742 dbus_message_iter_get_basic(&value, &username);
743 vpn_provider_set_string_hide_value(data->provider,
747 dbus_message_iter_next(&dict);
750 if (!password || !username) {
751 vpn_provider_indicate_error(data->provider,
752 VPN_PROVIDER_ERROR_AUTH_FAILED);
757 ov_return_credentials(data, username, password);
762 ov_connect_done(data, err);
765 static int request_credentials_input(struct ov_private_data *data)
767 DBusMessage *message;
768 const char *path, *agent_sender, *agent_path;
769 DBusMessageIter iter;
770 DBusMessageIter dict;
774 agent = connman_agent_get_info(data->dbus_sender, &agent_sender,
776 if (!agent || !agent_path)
779 message = dbus_message_new_method_call(agent_sender, agent_path,
785 dbus_message_iter_init_append(message, &iter);
787 path = vpn_provider_get_path(data->provider);
788 dbus_message_iter_append_basic(&iter,
789 DBUS_TYPE_OBJECT_PATH, &path);
791 connman_dbus_dict_open(&iter, &dict);
793 if (vpn_provider_get_authentication_errors(data->provider))
794 vpn_agent_append_auth_failure(&dict, data->provider, NULL);
796 /* Request temporary properties to pass on to openvpn */
797 connman_dbus_dict_append_dict(&dict, "OpenVPN.Username",
798 request_input_append_mandatory, NULL);
800 connman_dbus_dict_append_dict(&dict, "OpenVPN.Password",
801 request_input_append_password, NULL);
803 vpn_agent_append_host_and_name(&dict, data->provider);
805 connman_dbus_dict_close(&iter, &dict);
807 err = connman_agent_queue_message(data->provider, message,
808 connman_timeout_input_request(),
809 request_input_credentials_reply, data, agent);
811 if (err < 0 && err != -EBUSY) {
812 connman_error("error %d sending agent request", err);
813 dbus_message_unref(message);
818 dbus_message_unref(message);
823 static void request_input_private_key_reply(DBusMessage *reply,
826 struct ov_private_data *data = user_data;
827 const char *privatekeypass = NULL;
829 DBusMessageIter iter, dict;
833 connman_info("provider %p", data->provider);
836 * When connmand calls disconnect because of connection timeout no
844 dbus_error_init(&error);
846 err = vpn_agent_check_and_process_reply_error(reply, data->provider,
847 data->task, data->cb, data->user_data);
849 /* Ensure cb is called only once */
851 data->user_data = NULL;
855 if (!vpn_agent_check_reply_has_dict(reply)) {
860 dbus_message_iter_init(reply, &iter);
861 dbus_message_iter_recurse(&iter, &dict);
862 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
863 DBusMessageIter entry, value;
865 dbus_message_iter_recurse(&dict, &entry);
866 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
869 dbus_message_iter_get_basic(&entry, &key);
871 if (g_str_equal(key, "OpenVPN.PrivateKeyPassword")) {
872 dbus_message_iter_next(&entry);
873 if (dbus_message_iter_get_arg_type(&entry)
874 != DBUS_TYPE_VARIANT)
876 dbus_message_iter_recurse(&entry, &value);
877 if (dbus_message_iter_get_arg_type(&value)
880 dbus_message_iter_get_basic(&value, &privatekeypass);
881 vpn_provider_set_string_hide_value(data->provider,
882 key, privatekeypass);
886 dbus_message_iter_next(&dict);
889 if (!privatekeypass) {
890 vpn_provider_indicate_error(data->provider,
891 VPN_PROVIDER_ERROR_AUTH_FAILED);
897 ov_return_private_key_password(data, privatekeypass);
902 ov_connect_done(data, err);
905 static int request_private_key_input(struct ov_private_data *data)
907 DBusMessage *message;
908 const char *path, *agent_sender, *agent_path;
909 const char *privatekeypass;
910 DBusMessageIter iter;
911 DBusMessageIter dict;
916 * First check if this is the second attempt to get the key within
917 * this connection. In such case there has been invalid Private Key
918 * Password and it must be reset, and queried from user.
920 if (data->failed_attempts_privatekey) {
921 vpn_provider_set_string_hide_value(data->provider,
922 "OpenVPN.PrivateKeyPassword", NULL);
924 /* If the encrypted Private key password is kept in memory and
925 * use it first. If authentication fails this is cleared,
926 * likewise it is when connman-vpnd is restarted.
928 privatekeypass = vpn_provider_get_string(data->provider,
929 "OpenVPN.PrivateKeyPassword");
930 if (privatekeypass) {
931 ov_return_private_key_password(data, privatekeypass);
936 agent = connman_agent_get_info(data->dbus_sender, &agent_sender,
938 if (!agent || !agent_path)
941 message = dbus_message_new_method_call(agent_sender, agent_path,
947 dbus_message_iter_init_append(message, &iter);
949 path = vpn_provider_get_path(data->provider);
950 dbus_message_iter_append_basic(&iter,
951 DBUS_TYPE_OBJECT_PATH, &path);
953 connman_dbus_dict_open(&iter, &dict);
955 connman_dbus_dict_append_dict(&dict, "OpenVPN.PrivateKeyPassword",
956 request_input_append_password, NULL);
958 vpn_agent_append_host_and_name(&dict, data->provider);
960 /* Do not allow to store or retrieve the encrypted Private Key pass */
961 vpn_agent_append_allow_credential_storage(&dict, false);
962 vpn_agent_append_allow_credential_retrieval(&dict, false);
965 * Indicate to keep credentials, the enc Private Key password should
966 * not affect the credential storing.
968 vpn_agent_append_keep_credentials(&dict, true);
970 connman_dbus_dict_append_dict(&dict, "Enter Private Key password",
971 request_input_append_informational, NULL);
973 connman_dbus_dict_close(&iter, &dict);
975 err = connman_agent_queue_message(data->provider, message,
976 connman_timeout_input_request(),
977 request_input_private_key_reply, data, agent);
979 if (err < 0 && err != -EBUSY) {
980 connman_error("error %d sending agent request", err);
981 dbus_message_unref(message);
986 dbus_message_unref(message);
992 static gboolean ov_management_handle_input(GIOChannel *source,
993 GIOCondition condition, gpointer user_data)
995 struct ov_private_data *data = user_data;
1000 if (condition & G_IO_IN) {
1002 * Just return if line is not read and str is not allocated.
1003 * Condition check handles closing of the channel later.
1005 if (g_io_channel_read_line(source, &str, NULL, NULL, NULL) !=
1009 str[strlen(str) - 1] = '\0';
1010 connman_warn("openvpn request %s", str);
1012 if (g_str_has_prefix(str, ">PASSWORD:Need 'Auth'")) {
1014 * Request credentials from the user
1016 err = request_credentials_input(data);
1017 if (err != -EINPROGRESS)
1019 } else if (g_str_has_prefix(str,
1020 ">PASSWORD:Need 'Private Key'")) {
1021 err = request_private_key_input(data);
1022 if (err != -EINPROGRESS)
1024 } else if (g_str_has_prefix(str,
1025 ">PASSWORD:Verification Failed: 'Auth'")) {
1027 * Add error only, state change indication causes
1028 * signal to be sent, which is not desired when
1029 * OpenVPN is in interactive mode.
1031 vpn_provider_add_error(data->provider,
1032 VPN_PROVIDER_ERROR_AUTH_FAILED);
1034 * According to the OpenVPN manual about management interface
1035 * https://openvpn.net/community-resources/management-interface/
1036 * this should be received but it does not seem to be reported
1037 * when decrypting private key fails. This requires following
1038 * patch for OpenVPN (at least <= 2.4.5) in order to work:
1039 * https://git.sailfishos.org/mer-core/openvpn/blob/
1040 * 4f4b4af116292a207416c8a990392e35a6fc41af/rpm/privatekey-
1041 * passphrase-handling.diff
1043 } else if (g_str_has_prefix(str, ">PASSWORD:Verification "
1044 "Failed: 'Private Key'")) {
1045 data->failed_attempts_privatekey++;
1049 } else if (condition & (G_IO_ERR | G_IO_HUP)) {
1050 connman_warn("Management channel termination");
1055 close_management_interface(data);
1060 static int ov_management_connect_timer_cb(gpointer user_data)
1062 struct ov_private_data *data = user_data;
1064 if (!data->mgmt_channel) {
1065 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
1067 struct sockaddr_un remote;
1070 memset(&remote, 0, sizeof(remote));
1071 remote.sun_family = AF_UNIX;
1072 g_strlcpy(remote.sun_path, data->mgmt_path,
1073 sizeof(remote.sun_path));
1075 err = connect(fd, (struct sockaddr *)&remote,
1078 data->mgmt_channel = g_io_channel_unix_new(fd);
1079 data->mgmt_event_id =
1080 g_io_add_watch(data->mgmt_channel,
1081 G_IO_IN | G_IO_ERR | G_IO_HUP,
1082 ov_management_handle_input,
1085 connman_warn("Connected management socket");
1086 data->mgmt_timer_id = 0;
1087 return G_SOURCE_REMOVE;
1093 data->connect_attempts++;
1094 if (data->connect_attempts > 30) {
1095 connman_warn("Unable to connect management socket");
1096 data->mgmt_timer_id = 0;
1097 return G_SOURCE_REMOVE;
1100 return G_SOURCE_CONTINUE;
1103 static int ov_connect(struct vpn_provider *provider,
1104 struct connman_task *task, const char *if_name,
1105 vpn_provider_connect_cb_t cb, const char *dbus_sender,
1109 struct ov_private_data *data;
1111 data = g_try_new0(struct ov_private_data, 1);
1115 vpn_provider_set_plugin_data(provider, data);
1116 data->provider = vpn_provider_ref(provider);
1118 data->dbus_sender = g_strdup(dbus_sender);
1119 data->if_name = g_strdup(if_name);
1121 data->user_data = user_data;
1124 * We need to use the management interface to provide
1125 * the user credentials and password for decrypting private key.
1128 /* Use env TMPDIR for creating management socket, fall back to /tmp */
1129 tmpdir = getenv("TMPDIR");
1130 if (!tmpdir || !*tmpdir)
1133 /* Set up the path for the management interface */
1134 data->mgmt_path = g_strconcat(tmpdir, "/connman-vpn-management-",
1135 vpn_provider_get_ident(provider), NULL);
1136 if (unlink(data->mgmt_path) != 0 && errno != ENOENT) {
1137 connman_warn("Unable to unlink management socket %s: %d",
1138 data->mgmt_path, errno);
1141 data->mgmt_timer_id = g_timeout_add(200,
1142 ov_management_connect_timer_cb, data);
1144 task_append_config_data(provider, task);
1146 return run_connect(data, cb, user_data);
1149 static void ov_disconnect(struct vpn_provider *provider)
1154 connman_agent_cancel(provider);
1156 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
1159 static int ov_device_flags(struct vpn_provider *provider)
1163 option = vpn_provider_get_string(provider, "OpenVPN.DeviceType");
1168 if (g_str_equal(option, "tap")) {
1172 if (!g_str_equal(option, "tun")) {
1173 connman_warn("bad OpenVPN.DeviceType value "
1174 "falling back to tun");
1180 static int ov_route_env_parse(struct vpn_provider *provider, const char *key,
1181 int *family, unsigned long *idx,
1182 enum vpn_provider_route_type *type)
1187 if (g_str_has_prefix(key, "route_network_")) {
1188 start = key + strlen("route_network_");
1189 *type = VPN_PROVIDER_ROUTE_TYPE_ADDR;
1190 } else if (g_str_has_prefix(key, "route_netmask_")) {
1191 start = key + strlen("route_netmask_");
1192 *type = VPN_PROVIDER_ROUTE_TYPE_MASK;
1193 } else if (g_str_has_prefix(key, "route_gateway_")) {
1194 start = key + strlen("route_gateway_");
1195 *type = VPN_PROVIDER_ROUTE_TYPE_GW;
1200 *idx = g_ascii_strtoull(start, &end, 10);
1205 static struct vpn_driver vpn_driver = {
1206 .notify = ov_notify,
1207 .connect = ov_connect,
1208 .disconnect = ov_disconnect,
1210 .device_flags = ov_device_flags,
1211 .route_env_parse = ov_route_env_parse,
1214 static int openvpn_init(void)
1216 connection = connman_dbus_get_connection();
1218 return vpn_register("openvpn", &vpn_driver, OPENVPN);
1221 static void openvpn_exit(void)
1223 vpn_unregister("openvpn");
1225 dbus_connection_unref(connection);
1228 CONNMAN_PLUGIN_DEFINE(openvpn, "OpenVPN plugin", VERSION,
1229 CONNMAN_PLUGIN_PRIORITY_DEFAULT, openvpn_init, openvpn_exit)