1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
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.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 Novell, Inc.
19 * Copyright (C) 2008 Red Hat, Inc.
20 */
21
22 #include <string.h>
23 #include <pppd/pppd.h>
24 #include <pppd/fsm.h>
25 #include <pppd/ipcp.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <glib.h>
30 #include <glib-object.h>
31 #include <dbus/dbus-glib.h>
32
33 #include "NetworkManager.h"
34 #include "nm-pppd-plugin.h"
35 #include "nm-ppp-status.h"
36 #include "nm-dbus-glib-types.h"
37
38 int plugin_init (void);
39
40 char pppd_version[] = VERSION;
41
42 static DBusGProxy *proxy = NULL;
43
44 static void
45 nm_phasechange (void *data, int arg)
46 {
47 NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN;
48 char *ppp_phase;
49
50 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
51
52 switch (arg) {
53 case PHASE_DEAD:
54 ppp_status = NM_PPP_STATUS_DEAD;
55 ppp_phase = "dead";
56 break;
57 case PHASE_INITIALIZE:
58 ppp_status = NM_PPP_STATUS_INITIALIZE;
59 ppp_phase = "initialize";
60 break;
61 case PHASE_SERIALCONN:
62 ppp_status = NM_PPP_STATUS_SERIALCONN;
63 ppp_phase = "serial connection";
64 break;
65 case PHASE_DORMANT:
66 ppp_status = NM_PPP_STATUS_DORMANT;
67 ppp_phase = "dormant";
68 break;
69 case PHASE_ESTABLISH:
70 ppp_status = NM_PPP_STATUS_ESTABLISH;
71 ppp_phase = "establish";
72 break;
73 case PHASE_AUTHENTICATE:
74 ppp_status = NM_PPP_STATUS_AUTHENTICATE;
75 ppp_phase = "authenticate";
76 break;
77 case PHASE_CALLBACK:
78 ppp_status = NM_PPP_STATUS_CALLBACK;
79 ppp_phase = "callback";
80 break;
81 case PHASE_NETWORK:
82 ppp_status = NM_PPP_STATUS_NETWORK;
83 ppp_phase = "network";
84 break;
85 case PHASE_RUNNING:
86 ppp_status = NM_PPP_STATUS_RUNNING;
87 ppp_phase = "running";
88 break;
89 case PHASE_TERMINATE:
90 ppp_status = NM_PPP_STATUS_TERMINATE;
91 ppp_phase = "terminate";
92 break;
93 case PHASE_DISCONNECT:
94 ppp_status = NM_PPP_STATUS_DISCONNECT;
95 ppp_phase = "disconnect";
96 break;
97 case PHASE_HOLDOFF:
98 ppp_status = NM_PPP_STATUS_HOLDOFF;
99 ppp_phase = "holdoff";
100 break;
101 case PHASE_MASTER:
102 ppp_status = NM_PPP_STATUS_MASTER;
103 ppp_phase = "master";
104 break;
105
106 default:
107 ppp_phase = "unknown";
108 break;
109 }
110
111 g_message ("nm-ppp-plugin: (%s): status %d / phase '%s'",
112 __func__,
113 ppp_status,
114 ppp_phase);
115
116 if (ppp_status != NM_PPP_STATUS_UNKNOWN) {
117 dbus_g_proxy_call_no_reply (proxy, "SetState",
118 G_TYPE_UINT, ppp_status, G_TYPE_INVALID,
119 G_TYPE_INVALID);
120 }
121 }
122
123 static GValue *
124 str_to_gvalue (const char *str)
125 {
126 GValue *val;
127
128 val = g_slice_new0 (GValue);
129 g_value_init (val, G_TYPE_STRING);
130 g_value_set_string (val, str);
131
132 return val;
133 }
134
135 static GValue *
136 uint_to_gvalue (guint32 i)
137 {
138 GValue *val;
139
140 val = g_slice_new0 (GValue);
141 g_value_init (val, G_TYPE_UINT);
142 g_value_set_uint (val, i);
143
144 return val;
145 }
146
147 static void
148 value_destroy (gpointer data)
149 {
150 GValue *val = (GValue *) data;
151
152 g_value_unset (val);
153 g_slice_free (GValue, val);
154 }
155
156 static void
157 nm_ip_up (void *data, int arg)
158 {
159 ipcp_options opts = ipcp_gotoptions[0];
160 ipcp_options peer_opts = ipcp_hisoptions[0];
161 GHashTable *hash;
162 GArray *array;
163 GValue *val;
164 guint32 pppd_made_up_address = htonl (0x0a404040 + ifunit);
165
166 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
167
168 g_message ("nm-ppp-plugin: (%s): ip-up event", __func__);
169
170 if (!opts.ouraddr) {
171 g_warning ("nm-ppp-plugin: (%s): didn't receive an internal IP from pppd!", __func__);
172 nm_phasechange (NULL, PHASE_DEAD);
173 return;
174 }
175
176 hash = g_hash_table_new_full (g_str_hash, g_str_equal,
177 NULL, value_destroy);
178
179 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_INTERFACE,
180 str_to_gvalue (ifname));
181
182 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_ADDRESS,
183 uint_to_gvalue (opts.ouraddr));
184
185 /* Prefer the peer options remote address first, _unless_ pppd made the
186 * address up, at which point prefer the local options remote address,
187 * and if that's not right, use the made-up address as a last resort.
188 */
189 if (peer_opts.hisaddr && (peer_opts.hisaddr != pppd_made_up_address)) {
190 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_GATEWAY,
191 uint_to_gvalue (peer_opts.hisaddr));
192 } else if (opts.hisaddr) {
193 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_GATEWAY,
194 uint_to_gvalue (opts.hisaddr));
195 } else if (peer_opts.hisaddr == pppd_made_up_address) {
196 /* As a last resort, use the made-up address */
197 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_GATEWAY,
198 uint_to_gvalue (peer_opts.hisaddr));
199 }
200
201 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_PREFIX, uint_to_gvalue (32));
202
203 if (opts.dnsaddr[0] || opts.dnsaddr[1]) {
204 array = g_array_new (FALSE, FALSE, sizeof (guint32));
205
206 if (opts.dnsaddr[0])
207 g_array_append_val (array, opts.dnsaddr[0]);
208 if (opts.dnsaddr[1])
209 g_array_append_val (array, opts.dnsaddr[1]);
210
211 val = g_slice_new0 (GValue);
212 g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
213 g_value_set_boxed (val, array);
214
215 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_DNS, val);
216 }
217
218 if (opts.winsaddr[0] || opts.winsaddr[1]) {
219 array = g_array_new (FALSE, FALSE, sizeof (guint32));
220
221 if (opts.winsaddr[0])
222 g_array_append_val (array, opts.winsaddr[0]);
223 if (opts.winsaddr[1])
224 g_array_append_val (array, opts.winsaddr[1]);
225
226 val = g_slice_new0 (GValue);
227 g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
228 g_value_set_boxed (val, array);
229
230 g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_WINS, val);
231 }
232
233 g_message ("nm-ppp-plugin: (%s): sending Ip4Config to NetworkManager...", __func__);
234
235 dbus_g_proxy_call_no_reply (proxy, "SetIp4Config",
236 DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID,
237 G_TYPE_INVALID);
238
239 g_hash_table_destroy (hash);
240 }
241
242 static int
243 get_chap_check (void)
244 {
245 return 1;
246 }
247
248 static int
249 get_pap_check (void)
250 {
251 return 1;
252 }
253
254 static int
255 get_credentials (char *username, char *password)
256 {
257 char *my_username = NULL;
258 char *my_password = NULL;
259 size_t len;
260 GError *err = NULL;
261
(1) Event cond_false: |
Condition "username", taking false branch |
(3) Event var_compare_op: |
Comparing "username" to null implies that "username" might be null. |
Also see events: |
[var_deref_model] |
262 if (username && !password) {
263 /* pppd is checking pap support; return 1 for supported */
264 return 1;
(2) Event if_end: |
End of if statement |
265 }
266
(4) Event cond_true: |
Condition "!__inst", taking true branch |
(5) Event if_fallthrough: |
Falling through to end of if statement |
(6) Event if_end: |
End of if statement |
(7) Event cond_true: |
Condition "({...})", taking true branch |
(8) Event if_fallthrough: |
Falling through to end of if statement |
(9) Event if_end: |
End of if statement |
(10) Event cond_true: |
Condition "({...})", taking true branch |
(11) Event if_fallthrough: |
Falling through to end of if statement |
(12) Event if_end: |
End of if statement |
267 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), -1);
268
269 g_message ("nm-ppp-plugin: (%s): passwd-hook, requesting credentials...", __func__);
270
271 dbus_g_proxy_call (proxy, "NeedSecrets", &err,
272 G_TYPE_INVALID,
273 G_TYPE_STRING, &my_username,
274 G_TYPE_STRING, &my_password,
275 G_TYPE_INVALID);
276
(13) Event cond_false: |
Condition "err", taking false branch |
277 if (err) {
278 g_warning ("nm-ppp-plugin: (%s): could not get secrets: (%d) %s",
279 __func__,
280 err ? err->code : -1,
281 err->message ? err->message : "(unknown)");
282 g_error_free (err);
283 return -1;
(14) Event if_end: |
End of if statement |
284 }
285
286 g_message ("nm-ppp-plugin: (%s): got credentials from NetworkManager", __func__);
287
(15) Event cond_true: |
Condition "my_username", taking true branch |
288 if (my_username) {
289 len = strlen (my_username) + 1;
(16) Event cond_true: |
Condition "len < 256", taking true branch |
290 len = len < MAXNAMELEN ? len : MAXNAMELEN;
291
(17) Event var_deref_model: |
Passing null pointer "username" to function "strncpy(char * restrict, char const * restrict, size_t)", which dereferences it. |
Also see events: |
[var_compare_op] |
292 strncpy (username, my_username, len);
293 username[len - 1] = '\0';
294
295 g_free (my_username);
296 }
297
298 if (my_password) {
299 len = strlen (my_password) + 1;
300 len = len < MAXSECRETLEN ? len : MAXSECRETLEN;
301
302 strncpy (password, my_password, len);
303 password[len - 1] = '\0';
304
305 g_free (my_password);
306 }
307
308 return 1;
309 }
310
311 static void
312 nm_exit_notify (void *data, int arg)
313 {
314 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
315
316 g_message ("nm-ppp-plugin: (%s): cleaning up", __func__);
317
318 g_object_unref (proxy);
319 proxy = NULL;
320 }
321
322 int
323 plugin_init (void)
324 {
325 DBusGConnection *bus;
326 GError *err = NULL;
327
328 g_type_init ();
329
330 g_message ("nm-ppp-plugin: (%s): initializing", __func__);
331
332 bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
333 if (!bus) {
334 g_warning ("nm-pppd-plugin: (%s): couldn't connect to system bus: (%d) %s",
335 __func__,
336 err ? err->code : -1,
337 err && err->message ? err->message : "(unknown)");
338 g_error_free (err);
339 return -1;
340 }
341
342 /* NM passes in the object path of the corresponding PPPManager
343 * object as the 'ipparam' argument to pppd.
344 */
345 proxy = dbus_g_proxy_new_for_name (bus, NM_DBUS_SERVICE, ipparam, NM_DBUS_INTERFACE_PPP);
346
347 dbus_g_connection_unref (bus);
348
349 chap_passwd_hook = get_credentials;
350 chap_check_hook = get_chap_check;
351 pap_passwd_hook = get_credentials;
352 pap_check_hook = get_pap_check;
353
354 add_notifier (&phasechange, nm_phasechange, NULL);
355 add_notifier (&ip_up_notifier, nm_ip_up, NULL);
356 add_notifier (&exitnotify, nm_exit_notify, proxy);
357
358 return 0;
359 }
360