5 * Copyright (C) 2010,2013-2014 BMW Car IT GmbH.
6 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
7 * Copyright (C) 2019-2021 Jolla Ltd.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <dbus/dbus.h>
37 #define CONNMAN_API_SUBJECT_TO_CHANGE
38 #include <connman/plugin.h>
39 #include <connman/provider.h>
40 #include <connman/log.h>
41 #include <connman/task.h>
42 #include <connman/dbus.h>
43 #include <connman/inet.h>
44 #include <connman/agent.h>
45 #include <connman/setting.h>
46 #include <connman/vpn-dbus.h>
48 #include "../vpn-provider.h"
49 #include "../vpn-agent.h"
53 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
64 const char *pptp_default;
67 { "PPTP.User", "user", NULL, OPT_STRING },
68 { "PPTP.IdleWait", "--idle-wait", NULL, OPT_PPTP_ONLY},
69 { "PPTP.MaxEchoWait", "--max-echo-wait", NULL, OPT_PPTP_ONLY},
70 { "PPPD.EchoFailure", "lcp-echo-failure", "0", OPT_STRING },
71 { "PPPD.EchoInterval", "lcp-echo-interval", "0", OPT_STRING },
72 { "PPPD.Debug", "debug", NULL, OPT_STRING },
73 { "PPPD.RefuseEAP", "refuse-eap", NULL, OPT_BOOL },
74 { "PPPD.RefusePAP", "refuse-pap", NULL, OPT_BOOL },
75 { "PPPD.RefuseCHAP", "refuse-chap", NULL, OPT_BOOL },
76 { "PPPD.RefuseMSCHAP", "refuse-mschap", NULL, OPT_BOOL },
77 { "PPPD.RefuseMSCHAP2", "refuse-mschapv2", NULL, OPT_BOOL },
78 { "PPPD.NoBSDComp", "nobsdcomp", NULL, OPT_BOOL },
79 { "PPPD.NoDeflate", "nodeflate", NULL, OPT_BOOL },
80 { "PPPD.RequirMPPE", "require-mppe", NULL, OPT_BOOL },
81 { "PPPD.RequirMPPE40", "require-mppe-40", NULL, OPT_BOOL },
82 { "PPPD.RequirMPPE128", "require-mppe-128", NULL, OPT_BOOL },
83 { "PPPD.RequirMPPEStateful", "mppe-stateful", NULL, OPT_BOOL },
84 { "PPPD.NoVJ", "novj", NULL, OPT_BOOL },
87 static DBusConnection *connection;
89 struct pptp_private_data {
90 struct vpn_provider *provider;
91 struct connman_task *task;
93 vpn_provider_connect_cb_t cb;
97 static void pptp_connect_done(struct pptp_private_data *data, int err)
99 vpn_provider_connect_cb_t cb;
102 if (!data || !data->cb)
105 /* Ensure that callback is called only once */
107 user_data = data->user_data;
109 data->user_data = NULL;
110 cb(data->provider, user_data, err);
113 static void free_private_data(struct pptp_private_data *data)
115 if (vpn_provider_get_plugin_data(data->provider) == data)
116 vpn_provider_set_plugin_data(data->provider, NULL);
118 pptp_connect_done(data, EIO);
119 vpn_provider_unref(data->provider);
120 g_free(data->if_name);
124 static DBusMessage *pptp_get_sec(struct connman_task *task,
125 DBusMessage *msg, void *user_data)
127 const char *user, *passwd;
128 struct vpn_provider *provider = user_data;
131 if (dbus_message_get_no_reply(msg))
134 user = vpn_provider_get_string(provider, "PPTP.User");
135 passwd = vpn_provider_get_string(provider, "PPTP.Password");
136 if (!user || strlen(user) == 0 ||
137 !passwd || strlen(passwd) == 0)
140 reply = dbus_message_new_method_return(msg);
144 dbus_message_append_args(reply, DBUS_TYPE_STRING, &user,
145 DBUS_TYPE_STRING, &passwd,
150 static int pptp_notify(DBusMessage *msg, struct vpn_provider *provider)
152 DBusMessageIter iter, dict;
153 const char *reason, *key, *value;
154 char *addressv4 = NULL, *netmask = NULL, *gateway = NULL;
155 char *ifname = NULL, *nameservers = NULL;
156 struct connman_ipaddress *ipaddress = NULL;
157 struct pptp_private_data *data;
159 data = vpn_provider_get_plugin_data(provider);
161 dbus_message_iter_init(msg, &iter);
163 dbus_message_iter_get_basic(&iter, &reason);
164 dbus_message_iter_next(&iter);
167 connman_error("No provider found");
168 return VPN_STATE_FAILURE;
171 if (strcmp(reason, "auth failed") == 0) {
172 DBG("authentication failure");
174 vpn_provider_set_string(provider, "PPTP.User", NULL);
175 vpn_provider_set_string_hide_value(provider, "PPTP.Password",
178 pptp_connect_done(data, EACCES);
179 return VPN_STATE_AUTH_FAILURE;
182 if (strcmp(reason, "connect")) {
183 pptp_connect_done(data, EIO);
186 * Stop the task to avoid potential looping of this state when
187 * authentication fails.
189 if (data && data->task)
190 connman_task_stop(data->task);
192 return VPN_STATE_DISCONNECT;
195 dbus_message_iter_recurse(&iter, &dict);
197 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
198 DBusMessageIter entry;
200 dbus_message_iter_recurse(&dict, &entry);
201 dbus_message_iter_get_basic(&entry, &key);
202 dbus_message_iter_next(&entry);
203 dbus_message_iter_get_basic(&entry, &value);
205 DBG("%s = %s", key, value);
207 if (!strcmp(key, "INTERNAL_IP4_ADDRESS"))
208 addressv4 = g_strdup(value);
210 if (!strcmp(key, "INTERNAL_IP4_NETMASK"))
211 netmask = g_strdup(value);
213 if (!strcmp(key, "INTERNAL_IP4_DNS"))
214 nameservers = g_strdup(value);
216 if (!strcmp(key, "INTERNAL_IFNAME"))
217 ifname = g_strdup(value);
219 dbus_message_iter_next(&dict);
222 if (vpn_set_ifname(provider, ifname) < 0) {
227 return VPN_STATE_FAILURE;
231 ipaddress = connman_ipaddress_alloc(AF_INET);
236 connman_error("No IP address for provider");
240 return VPN_STATE_FAILURE;
243 value = vpn_provider_get_string(provider, "HostIP");
245 vpn_provider_set_string(provider, "Gateway", value);
246 gateway = g_strdup(value);
250 connman_ipaddress_set_ipv4(ipaddress, addressv4, netmask,
253 connman_ipaddress_set_p2p(ipaddress, true);
254 vpn_provider_set_ipaddress(provider, ipaddress);
255 vpn_provider_set_nameservers(provider, nameservers);
261 connman_ipaddress_free(ipaddress);
263 pptp_connect_done(data, 0);
264 return VPN_STATE_CONNECT;
267 static int pptp_save(struct vpn_provider *provider, GKeyFile *keyfile)
270 bool pptp_option, pppd_option;
273 for (i = 0; i < (int)ARRAY_SIZE(pptp_options); i++) {
274 pptp_option = pppd_option = false;
276 if (strncmp(pptp_options[i].cm_opt, "PPTP.", 5) == 0)
279 if (strncmp(pptp_options[i].cm_opt, "PPPD.", 5) == 0)
282 if (pptp_option || pppd_option) {
283 option = vpn_provider_get_string(provider,
284 pptp_options[i].cm_opt);
287 * Check if the option prefix is PPTP as the
288 * PPPD options were using PPTP prefix earlier.
295 pptp_str = g_strdup_printf("PPTP.%s",
296 &pptp_options[i].cm_opt[5]);
297 option = vpn_provider_get_string(provider,
305 g_key_file_set_string(keyfile,
306 vpn_provider_get_save_group(provider),
307 pptp_options[i].cm_opt, option);
314 static void pptp_write_bool_option(struct connman_task *task,
315 const char *key, const char *value)
318 if (strcasecmp(value, "yes") == 0 ||
319 strcasecmp(value, "true") == 0 ||
320 strcmp(value, "1") == 0)
321 connman_task_add_argument(task, key, NULL);
325 static void pptp_died(struct connman_task *task, int exit_code,
328 struct pptp_private_data *data = user_data;
330 vpn_died(task, exit_code, data->provider);
332 free_private_data(data);
335 struct request_input_reply {
336 struct vpn_provider *provider;
337 vpn_provider_password_cb_t callback;
341 static void request_input_reply(DBusMessage *reply, void *user_data)
343 struct request_input_reply *pptp_reply = user_data;
344 struct pptp_private_data *data;
345 const char *error = NULL;
346 char *username = NULL, *password = NULL;
348 DBusMessageIter iter, dict;
351 DBG("provider %p", pptp_reply->provider);
356 data = pptp_reply->user_data;
358 err = vpn_agent_check_and_process_reply_error(reply,
359 pptp_reply->provider, data->task, data->cb,
362 /* Ensure cb is called only once */
364 data->user_data = NULL;
365 error = dbus_message_get_error_name(reply);
369 if (!vpn_agent_check_reply_has_dict(reply))
372 dbus_message_iter_init(reply, &iter);
373 dbus_message_iter_recurse(&iter, &dict);
374 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
375 DBusMessageIter entry, value;
378 dbus_message_iter_recurse(&dict, &entry);
379 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
382 dbus_message_iter_get_basic(&entry, &key);
384 if (g_str_equal(key, "Username")) {
385 dbus_message_iter_next(&entry);
386 if (dbus_message_iter_get_arg_type(&entry)
387 != DBUS_TYPE_VARIANT)
389 dbus_message_iter_recurse(&entry, &value);
390 if (dbus_message_iter_get_arg_type(&value)
393 dbus_message_iter_get_basic(&value, &str);
394 username = g_strdup(str);
397 if (g_str_equal(key, "Password")) {
398 dbus_message_iter_next(&entry);
399 if (dbus_message_iter_get_arg_type(&entry)
400 != DBUS_TYPE_VARIANT)
402 dbus_message_iter_recurse(&entry, &value);
403 if (dbus_message_iter_get_arg_type(&value)
406 dbus_message_iter_get_basic(&value, &str);
407 password = g_strdup(str);
410 dbus_message_iter_next(&dict);
414 pptp_reply->callback(pptp_reply->provider, username, password, error,
415 pptp_reply->user_data);
423 typedef void (* request_cb_t)(struct vpn_provider *provider,
424 const char *username, const char *password,
425 const char *error, void *user_data);
427 static int request_input(struct vpn_provider *provider,
428 request_cb_t callback, const char *dbus_sender,
431 DBusMessage *message;
432 const char *path, *agent_sender, *agent_path;
433 DBusMessageIter iter;
434 DBusMessageIter dict;
435 struct request_input_reply *pptp_reply;
439 agent = connman_agent_get_info(dbus_sender, &agent_sender,
441 if (!provider || !agent || !agent_path || !callback)
444 message = dbus_message_new_method_call(agent_sender, agent_path,
450 dbus_message_iter_init_append(message, &iter);
452 path = vpn_provider_get_path(provider);
453 dbus_message_iter_append_basic(&iter,
454 DBUS_TYPE_OBJECT_PATH, &path);
456 connman_dbus_dict_open(&iter, &dict);
458 if (vpn_provider_get_authentication_errors(provider))
459 vpn_agent_append_auth_failure(&dict, provider, NULL);
461 vpn_agent_append_user_info(&dict, provider, "PPTP.User");
463 vpn_agent_append_host_and_name(&dict, provider);
465 connman_dbus_dict_close(&iter, &dict);
467 pptp_reply = g_try_new0(struct request_input_reply, 1);
469 dbus_message_unref(message);
473 pptp_reply->provider = provider;
474 pptp_reply->callback = callback;
475 pptp_reply->user_data = user_data;
477 err = connman_agent_queue_message(provider, message,
478 connman_timeout_input_request(),
479 request_input_reply, pptp_reply, agent);
480 if (err < 0 && err != -EBUSY) {
481 DBG("error %d sending agent request", err);
482 dbus_message_unref(message);
487 dbus_message_unref(message);
492 static int run_connect(struct pptp_private_data *data, const char *username,
493 const char *password)
495 struct vpn_provider *provider = data->provider;
496 struct connman_task *task = data->task;
503 if (!username || !*username || !password || !*password) {
504 DBG("Cannot connect username %s password %p",
510 DBG("username %s password %p", username, password);
512 host = vpn_provider_get_string(provider, "Host");
514 /* Create PPTP options for pppd "pty" */
515 pptp_opt_s = g_string_new(NULL);
516 g_string_append_printf(pptp_opt_s, "%s %s --nolaunchpppd --loglevel 2",
519 connman_task_add_argument(task, "nodetach", NULL);
520 connman_task_add_argument(task, "lock", NULL);
521 connman_task_add_argument(task, "logfd", "2");
522 connman_task_add_argument(task, "usepeerdns", NULL);
523 connman_task_add_argument(task, "noipdefault", NULL);
524 connman_task_add_argument(task, "noauth", NULL);
525 connman_task_add_argument(task, "nodefaultroute", NULL);
526 connman_task_add_argument(task, "ipparam", "pptp_plugin");
528 for (i = 0; i < (int)ARRAY_SIZE(pptp_options); i++) {
529 opt_s = vpn_provider_get_string(provider,
530 pptp_options[i].cm_opt);
532 opt_s = pptp_options[i].pptp_default;
537 if (pptp_options[i].type == OPT_STRING)
538 connman_task_add_argument(task,
539 pptp_options[i].pptp_opt, opt_s);
540 else if (pptp_options[i].type == OPT_BOOL)
541 pptp_write_bool_option(task,
542 pptp_options[i].pptp_opt, opt_s);
543 else if (pptp_options[i].type == OPT_PPTP_ONLY)
544 g_string_append_printf(pptp_opt_s, " %s %s",
545 pptp_options[i].pptp_opt, opt_s);
548 str = g_string_free(pptp_opt_s, FALSE);
549 connman_task_add_argument(task, "pty", str);
552 connman_task_add_argument(task, "plugin",
553 SCRIPTDIR "/libppp-plugin.so");
555 err = connman_task_run(task, pptp_died, data, NULL, NULL, NULL);
557 connman_error("pptp failed to start");
563 pptp_connect_done(data, -err);
568 static void request_input_cb(struct vpn_provider *provider,
569 const char *username,
570 const char *password,
571 const char *error, void *user_data)
573 struct pptp_private_data *data = user_data;
575 if (!username || !*username || !password || !*password)
576 DBG("Requesting username %s or password failed, error %s",
579 DBG("error %s", error);
581 vpn_provider_set_string(provider, "PPTP.User", username);
582 vpn_provider_set_string_hide_value(provider, "PPTP.Password",
585 run_connect(data, username, password);
588 static int pptp_connect(struct vpn_provider *provider,
589 struct connman_task *task, const char *if_name,
590 vpn_provider_connect_cb_t cb, const char *dbus_sender,
593 struct pptp_private_data *data;
594 const char *username, *password;
597 data = g_try_new0(struct pptp_private_data, 1);
601 data->provider = vpn_provider_ref(provider);
603 data->if_name = g_strdup(if_name);
605 data->user_data = user_data;
606 vpn_provider_set_plugin_data(provider, data);
608 DBG("iface %s provider %p user %p", if_name, provider, user_data);
610 if (connman_task_set_notify(task, "getsec",
611 pptp_get_sec, provider)) {
616 username = vpn_provider_get_string(provider, "PPTP.User");
617 password = vpn_provider_get_string(provider, "PPTP.Password");
619 DBG("user %s password %p", username, password);
621 if (!username || !*username || !password || !*password) {
622 err = request_input(provider, request_input_cb, dbus_sender,
624 if (err != -EINPROGRESS)
630 return run_connect(data, username, password);
633 pptp_connect_done(data, -err);
634 free_private_data(data);
639 static int pptp_error_code(struct vpn_provider *provider, int exit_code)
644 return CONNMAN_PROVIDER_ERROR_CONNECT_FAILED;
646 return CONNMAN_PROVIDER_ERROR_LOGIN_FAILED;
648 return CONNMAN_PROVIDER_ERROR_AUTH_FAILED;
650 return CONNMAN_PROVIDER_ERROR_UNKNOWN;
654 static void pptp_disconnect(struct vpn_provider *provider)
659 vpn_provider_set_string_hide_value(provider, "PPTP.Password", NULL);
661 connman_agent_cancel(provider);
664 static struct vpn_driver vpn_driver = {
665 .flags = VPN_FLAG_NO_TUN,
666 .notify = pptp_notify,
667 .connect = pptp_connect,
668 .error_code = pptp_error_code,
670 .disconnect = pptp_disconnect,
673 static int pptp_init(void)
675 connection = connman_dbus_get_connection();
677 return vpn_register("pptp", &vpn_driver, PPPD);
680 static void pptp_exit(void)
682 vpn_unregister("pptp");
684 dbus_connection_unref(connection);
687 CONNMAN_PLUGIN_DEFINE(pptp, "pptp plugin", VERSION,
688 CONNMAN_PLUGIN_PRIORITY_DEFAULT, pptp_init, pptp_exit)