pptp: Add ppp plugin library
authorMohamed Abbas <mabbas@linux.intel.com>
Tue, 15 Nov 2011 11:06:17 +0000 (13:06 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Tue, 15 Nov 2011 12:41:44 +0000 (13:41 +0100)
pppd will use this library to talk with connman vpn plugin.

Original patch comes from Mohamed Abbas. Prepared for inclusion
by Jukka Rissanen, also changed the pptp function prefix to ppp as
the plugin is used by both pptp and l2tp plugins.

scripts/libppp-plugin.c [new file with mode: 0644]

diff --git a/scripts/libppp-plugin.c b/scripts/libppp-plugin.c
new file mode 100644 (file)
index 0000000..ba79db0
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/ipcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dbus/dbus.h>
+
+#define INET_ADDRES_LEN (INET_ADDRSTRLEN + 5)
+#define INET_DNS_LEN   (2*INET_ADDRSTRLEN + 9)
+
+static char *busname;
+static char *interface;
+static char *path;
+
+static DBusConnection *connection;
+
+char pppd_version[] = VERSION;
+
+int plugin_init(void);
+
+static void append(DBusMessageIter *dict, const char *key, const char *value)
+{
+       DBusMessageIter entry;
+
+       /* We clean the environment before invoking pppd, but
+        * might as well still filter out the few things that get
+        * added that we're not interested in
+        */
+       if (!strcmp(key, "PWD") || !strcmp(key, "_") ||
+                       !strcmp(key, "SHLVL") ||
+                       !strcmp(key, "connman_busname") ||
+                       !strcmp(key, "connman_network"))
+               return;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+
+static int ppp_have_secret()
+{
+       return 1;
+}
+
+static int ppp_get_secret(char *username, char *password)
+{
+       DBusMessage *msg, *reply;
+       const char *user, *pass;
+       DBusError err;
+
+       if (username == NULL && password == NULL)
+               return -1;
+
+       if (password == NULL)
+               return 1;
+
+       if (connection == NULL)
+               return -1;
+
+       dbus_error_init(&err);
+
+       msg = dbus_message_new_method_call(busname, path, interface, "getsec");
+       if (msg == NULL)
+               return -1;
+
+       dbus_message_append_args(msg, DBUS_TYPE_INVALID, DBUS_TYPE_INVALID);
+
+       reply = dbus_connection_send_with_reply_and_block(connection,
+                                                               msg, -1, &err);
+       if (reply == NULL) {
+               if (dbus_error_is_set(&err) == TRUE)
+                       dbus_error_free(&err);
+
+               dbus_message_unref(msg);
+               return -1;
+       }
+
+       dbus_message_unref(msg);
+
+       dbus_error_init(&err);
+
+       if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &user,
+                                               DBUS_TYPE_STRING, &pass,
+                                               DBUS_TYPE_INVALID) == FALSE) {
+               if (dbus_error_is_set(&err) == TRUE)
+                       dbus_error_free(&err);
+
+               dbus_message_unref(reply);
+               return -1;
+       }
+
+       if (username != NULL)
+               strcpy(username, user);
+
+       strcpy(password, pass);
+
+       dbus_message_unref(reply);
+
+       return 1;
+}
+
+static void ppp_up(void *data, int arg)
+{
+       char buf[INET_ADDRES_LEN];
+       char dns[INET_DNS_LEN];
+       const char *reason = "connect";
+       bool add_blank = FALSE;
+       DBusMessageIter iter, dict;
+       DBusMessage *msg;
+
+       if (connection == NULL)
+               return;
+
+       if (ipcp_gotoptions[0].ouraddr == 0)
+               return;
+
+       msg = dbus_message_new_method_call(busname, path,
+                                               interface, "notify");
+       if (msg == NULL)
+               return;
+
+       dbus_message_set_no_reply(msg, TRUE);
+
+       dbus_message_append_args(msg,
+                       DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       append(&dict, "INTERNAL_IFNAME", ifname);
+
+       inet_ntop(AF_INET, &ipcp_gotoptions[0].ouraddr, buf, INET_ADDRSTRLEN);
+       append(&dict, "INTERNAL_IP4_ADDRESS", buf);
+
+       strcpy(buf, "255.255.255.255");
+       append(&dict, "INTERNAL_IP4_NETMASK", buf);
+
+       if (ipcp_gotoptions[0].dnsaddr[0] || ipcp_gotoptions[0].dnsaddr[1]) {
+               memset(dns, 0, sizeof(dns));
+               dns[0] = '\0';
+
+               if (ipcp_gotoptions[0].dnsaddr[0]) {
+                       inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[0],
+                                                       buf, INET_ADDRSTRLEN);
+                       strcat(dns, buf);
+
+                       add_blank = TRUE;
+               }
+
+               if (ipcp_gotoptions[0].dnsaddr[1]) {
+                       inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[1],
+                                                       buf, INET_ADDRSTRLEN);
+                       if (add_blank == TRUE)
+                               strcat(dns, " ");
+
+                       strcat(dns, buf);
+               }
+               append(&dict, "INTERNAL_IP4_DNS", dns);
+       }
+
+       append(&dict, "MTU", "1400");
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_connection_send(connection, msg, NULL);
+
+       dbus_connection_flush(connection);
+
+       dbus_message_unref(msg);
+}
+
+static void ppp_exit(void *data, int arg)
+{
+       if (connection != NULL) {
+               dbus_connection_unref(connection);
+               connection = NULL;
+       }
+
+       if (busname != NULL) {
+               free(busname);
+               busname = NULL;
+       }
+
+       if (interface != NULL) {
+               free(interface);
+               interface = NULL;
+       }
+
+       if (path != NULL) {
+               free(path);
+               path = NULL;
+       }
+}
+
+static void ppp_phase_change(void *data, int arg)
+{
+       const char *reason = "disconnect";
+       DBusMessage *msg;
+
+       if (connection == NULL)
+               return;
+
+       if (arg == PHASE_DEAD || arg == PHASE_DISCONNECT) {
+               msg = dbus_message_new_method_call(busname, path,
+                                               interface, "notify");
+               if (msg == NULL)
+                       return;
+
+               dbus_message_set_no_reply(msg, TRUE);
+
+               dbus_message_append_args(msg,
+                       DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
+
+               dbus_connection_send(connection, msg, NULL);
+
+               dbus_connection_flush(connection);
+
+               dbus_message_unref(msg);
+       }
+}
+
+int plugin_init(void)
+{
+       DBusError error;
+       static const char *bus, *inter, *p;
+
+       dbus_error_init(&error);
+
+       bus = getenv("CONNMAN_BUSNAME");
+       inter = getenv("CONNMAN_INTERFACE");
+       p = getenv("CONNMAN_PATH");
+
+       if (bus == NULL || inter == NULL || p == NULL)
+               return -1;
+
+       busname = strdup(bus);
+       interface = strdup(inter);
+       path = strdup(p);
+
+       if (busname == NULL || interface == NULL || path == NULL) {
+               ppp_exit(NULL, 0);
+               return -1;
+       }
+
+       connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+       if (connection == NULL) {
+               if (dbus_error_is_set(&error) == TRUE)
+                       dbus_error_free(&error);
+
+               ppp_exit(NULL, 0);
+               return -1;
+       }
+
+       pap_passwd_hook = ppp_get_secret;
+       chap_passwd_hook = ppp_get_secret;
+
+       chap_check_hook = ppp_have_secret;
+       pap_check_hook = ppp_have_secret;
+
+       add_notifier(&ip_up_notifier, ppp_up, NULL);
+       add_notifier(&phasechange, ppp_phase_change, NULL);
+       add_notifier(&exitnotify, ppp_exit, connection);
+
+       return 0;
+}