5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/types.h>
32 #include <pppd/pppd.h>
34 #include <pppd/ipcp.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
38 #include <dbus/dbus.h>
40 #define INET_ADDRES_LEN (INET_ADDRSTRLEN + 5)
41 #define INET_DNS_LEN (2*INET_ADDRSTRLEN + 9)
44 static char *interface;
47 static DBusConnection *connection;
48 static int prev_phase;
50 char pppd_version[] = VERSION;
52 int plugin_init(void);
54 static void append(DBusMessageIter *dict, const char *key, const char *value)
56 DBusMessageIter entry;
58 /* We clean the environment before invoking pppd, but
59 * might as well still filter out the few things that get
60 * added that we're not interested in
62 if (!strcmp(key, "PWD") || !strcmp(key, "_") ||
63 !strcmp(key, "SHLVL") ||
64 !strcmp(key, "connman_busname") ||
65 !strcmp(key, "connman_network"))
68 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
71 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
73 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
75 dbus_message_iter_close_container(dict, &entry);
79 static int ppp_have_secret()
84 static int ppp_get_secret(char *username, char *password)
86 DBusMessage *msg, *reply;
87 const char *user, *pass;
90 if (username == NULL && password == NULL)
96 if (connection == NULL)
99 dbus_error_init(&err);
101 msg = dbus_message_new_method_call(busname, path, interface, "getsec");
105 dbus_message_append_args(msg, DBUS_TYPE_INVALID, DBUS_TYPE_INVALID);
107 reply = dbus_connection_send_with_reply_and_block(connection,
110 if (dbus_error_is_set(&err) == TRUE)
111 dbus_error_free(&err);
113 dbus_message_unref(msg);
117 dbus_message_unref(msg);
119 dbus_error_init(&err);
121 if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &user,
122 DBUS_TYPE_STRING, &pass,
123 DBUS_TYPE_INVALID) == FALSE) {
124 if (dbus_error_is_set(&err) == TRUE)
125 dbus_error_free(&err);
127 dbus_message_unref(reply);
131 if (username != NULL)
132 strcpy(username, user);
134 strcpy(password, pass);
136 dbus_message_unref(reply);
141 static void ppp_up(void *data, int arg)
143 char buf[INET_ADDRES_LEN];
144 char dns[INET_DNS_LEN];
145 const char *reason = "connect";
146 bool add_blank = FALSE;
147 DBusMessageIter iter, dict;
150 if (connection == NULL)
153 if (ipcp_gotoptions[0].ouraddr == 0)
156 msg = dbus_message_new_method_call(busname, path,
157 interface, "notify");
161 dbus_message_set_no_reply(msg, TRUE);
163 dbus_message_append_args(msg,
164 DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
166 dbus_message_iter_init_append(msg, &iter);
168 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
169 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
170 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
171 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
173 append(&dict, "INTERNAL_IFNAME", ifname);
175 inet_ntop(AF_INET, &ipcp_gotoptions[0].ouraddr, buf, INET_ADDRSTRLEN);
176 append(&dict, "INTERNAL_IP4_ADDRESS", buf);
178 strcpy(buf, "255.255.255.255");
179 append(&dict, "INTERNAL_IP4_NETMASK", buf);
181 if (ipcp_gotoptions[0].dnsaddr[0] || ipcp_gotoptions[0].dnsaddr[1]) {
182 memset(dns, 0, sizeof(dns));
185 if (ipcp_gotoptions[0].dnsaddr[0]) {
186 inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[0],
187 buf, INET_ADDRSTRLEN);
193 if (ipcp_gotoptions[0].dnsaddr[1]) {
194 inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[1],
195 buf, INET_ADDRSTRLEN);
196 if (add_blank == TRUE)
201 append(&dict, "INTERNAL_IP4_DNS", dns);
204 append(&dict, "MTU", "1400");
206 dbus_message_iter_close_container(&iter, &dict);
208 dbus_connection_send(connection, msg, NULL);
210 dbus_connection_flush(connection);
212 dbus_message_unref(msg);
215 static void ppp_exit(void *data, int arg)
217 if (connection != NULL) {
218 dbus_connection_unref(connection);
222 if (busname != NULL) {
227 if (interface != NULL) {
238 static void ppp_phase_change(void *data, int arg)
240 const char *reason = "disconnect";
244 if (connection == NULL)
247 if (prev_phase == PHASE_AUTHENTICATE &&
248 arg == PHASE_TERMINATE) {
249 reason = "auth failed";
253 if (send_msg > 0 || arg == PHASE_DEAD || arg == PHASE_DISCONNECT) {
254 msg = dbus_message_new_method_call(busname, path,
255 interface, "notify");
259 dbus_message_set_no_reply(msg, TRUE);
261 dbus_message_append_args(msg,
262 DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
264 dbus_connection_send(connection, msg, NULL);
266 dbus_connection_flush(connection);
268 dbus_message_unref(msg);
274 int plugin_init(void)
277 static const char *bus, *inter, *p;
279 dbus_error_init(&error);
281 bus = getenv("CONNMAN_BUSNAME");
282 inter = getenv("CONNMAN_INTERFACE");
283 p = getenv("CONNMAN_PATH");
285 if (bus == NULL || inter == NULL || p == NULL)
288 busname = strdup(bus);
289 interface = strdup(inter);
292 if (busname == NULL || interface == NULL || path == NULL) {
297 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
298 if (connection == NULL) {
299 if (dbus_error_is_set(&error) == TRUE)
300 dbus_error_free(&error);
306 pap_passwd_hook = ppp_get_secret;
307 chap_passwd_hook = ppp_get_secret;
309 chap_check_hook = ppp_have_secret;
310 pap_check_hook = ppp_have_secret;
312 add_notifier(&ip_up_notifier, ppp_up, NULL);
313 add_notifier(&phasechange, ppp_phase_change, NULL);
314 add_notifier(&exitnotify, ppp_exit, connection);