1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
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.
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.
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.
18 * Copyright (C) 2005 - 2012 Red Hat, Inc.
19 * Copyright (C) 2007 - 2008 Novell, Inc.
22 #include "nm-default.h"
29 #include "nm-activation-request.h"
30 #include "nm-setting-wireless-security.h"
31 #include "nm-setting-8021x.h"
32 #include "nm-device.h"
33 #include "nm-active-connection.h"
34 #include "nm-settings-connection.h"
35 #include "nm-auth-subject.h"
37 G_DEFINE_TYPE (NMActRequest, nm_act_request, NM_TYPE_ACTIVE_CONNECTION)
39 #define NM_ACT_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
40 NM_TYPE_ACT_REQUEST, \
49 GSList *secrets_calls;
52 } NMActRequestPrivate;
64 /*******************************************************************/
66 NMSettingsConnection *
67 nm_act_request_get_settings_connection (NMActRequest *req)
69 g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
71 return nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (req));
75 nm_act_request_get_applied_connection (NMActRequest *req)
77 g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
79 return nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (req));
82 /*******************************************************************/
84 struct _NMActRequestGetSecretsCallId {
86 NMActRequestSecretsFunc callback;
87 gpointer callback_data;
88 NMSettingsConnectionCallId call_id;
91 typedef struct _NMActRequestGetSecretsCallId GetSecretsInfo;
93 static GetSecretsInfo *
94 _get_secrets_info_new (NMActRequest *self, NMActRequestSecretsFunc callback, gpointer callback_data)
98 info = g_slice_new0 (GetSecretsInfo);
100 info->callback = callback;
101 info->callback_data = callback_data;
107 _get_secrets_info_free (GetSecretsInfo *info)
109 g_slice_free (GetSecretsInfo, info);
113 get_secrets_cb (NMSettingsConnection *connection,
114 NMSettingsConnectionCallId call_id_s,
115 const char *agent_username,
116 const char *setting_name,
120 GetSecretsInfo *info = user_data;
121 NMActRequestPrivate *priv;
123 g_return_if_fail (info && info->call_id == call_id_s);
124 g_return_if_fail (NM_IS_ACT_REQUEST (info->self));
126 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
129 priv = NM_ACT_REQUEST_GET_PRIVATE (info->self);
131 g_return_if_fail (g_slist_find (priv->secrets_calls, info));
133 priv->secrets_calls = g_slist_remove (priv->secrets_calls, info);
136 info->callback (info->self, info, connection, error, info->callback_data);
138 _get_secrets_info_free (info);
142 * nm_act_request_get_secrets:
150 * Asnychronously starts the request for secrets. This function cannot
153 * The return call-id can be used to cancel the request. You are
154 * only allowed to cancel a still pending operation (once).
155 * The callback will always be invoked once, even for canceling
156 * or disposing of NMActRequest.
158 * Returns: a call-id.
160 NMActRequestGetSecretsCallId
161 nm_act_request_get_secrets (NMActRequest *self,
162 const char *setting_name,
163 NMSecretAgentGetSecretsFlags flags,
165 NMActRequestSecretsFunc callback,
166 gpointer callback_data)
168 NMActRequestPrivate *priv;
169 GetSecretsInfo *info;
170 NMSettingsConnectionCallId call_id_s;
171 NMSettingsConnection *settings_connection;
172 NMConnection *applied_connection;
173 const char *hints[2] = { hint, NULL };
175 g_return_val_if_fail (NM_IS_ACT_REQUEST (self), 0);
177 priv = NM_ACT_REQUEST_GET_PRIVATE (self);
179 settings_connection = nm_act_request_get_settings_connection (self);
180 applied_connection = nm_act_request_get_applied_connection (self);
182 info = _get_secrets_info_new (self, callback, callback_data);
184 priv->secrets_calls = g_slist_append (priv->secrets_calls, info);
186 if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self)))
187 flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED;
189 call_id_s = nm_settings_connection_get_secrets (settings_connection,
191 nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)),
197 info->call_id = call_id_s;
198 g_return_val_if_fail (call_id_s, NULL);
203 _do_cancel_secrets (NMActRequest *self, GetSecretsInfo *info, gboolean is_disposing)
205 NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
207 nm_assert (info && info->self == self);
208 nm_assert (g_slist_find (priv->secrets_calls, info));
210 priv->secrets_calls = g_slist_remove (priv->secrets_calls, info);
212 nm_settings_connection_cancel_secrets (nm_act_request_get_settings_connection (self), info->call_id);
214 if (info->callback) {
215 gs_free_error GError *error = NULL;
217 nm_utils_error_set_cancelled (&error, is_disposing, "NMActRequest");
218 info->callback (self, info, NULL, error, info->callback_data);
221 _get_secrets_info_free (info);
225 nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId call_id)
227 NMActRequestPrivate *priv;
229 g_return_if_fail (NM_IS_ACT_REQUEST (self));
230 g_return_if_fail (call_id);
232 priv = NM_ACT_REQUEST_GET_PRIVATE (self);
234 if (!g_slist_find (priv->secrets_calls, call_id))
235 g_return_if_reached ();
237 _do_cancel_secrets (self, call_id, FALSE);
241 nm_act_request_clear_secrets (NMActRequest *self)
243 g_return_if_fail (NM_IS_ACT_REQUEST (self));
245 nm_active_connection_clear_secrets ((NMActiveConnection *) self);
248 /********************************************************************/
251 clear_share_rules (NMActRequest *req)
253 NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
256 for (iter = priv->share_rules; iter; iter = g_slist_next (iter)) {
257 ShareRule *rule = (ShareRule *) iter->data;
259 g_free (rule->table);
264 g_slist_free (priv->share_rules);
265 priv->share_rules = NULL;
269 nm_act_request_set_shared (NMActRequest *req, gboolean shared)
271 NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
274 g_return_if_fail (NM_IS_ACT_REQUEST (req));
276 NM_ACT_REQUEST_GET_PRIVATE (req)->shared = shared;
278 /* Tear the rules down in reverse order when sharing is stopped */
279 list = g_slist_copy (priv->share_rules);
281 list = g_slist_reverse (list);
283 /* Send the rules to iptables */
284 for (iter = list; iter; iter = g_slist_next (iter)) {
285 ShareRule *rule = (ShareRule *) iter->data;
286 char *envp[1] = { NULL };
287 gs_strfreev char **argv = NULL;
288 gs_free char *cmd = NULL;
290 cmd = g_strdup_printf ("%s --table %s %s %s",
293 shared ? "--insert" : "--delete",
298 argv = g_strsplit (cmd, " ", 0);
299 if (argv && argv[0]) {
301 GError *error = NULL;
303 nm_log_info (LOGD_SHARING, "Executing: %s", cmd);
304 if (!g_spawn_sync ("/", argv, envp, G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
305 NULL, NULL, NULL, NULL, &status, &error)) {
306 nm_log_warn (LOGD_SHARING, "Error executing command: %s",
308 g_clear_error (&error);
309 } else if (WEXITSTATUS (status)) {
310 nm_log_warn (LOGD_SHARING, "** Command returned exit status %d.",
311 WEXITSTATUS (status));
318 /* Clear the share rule list when sharing is stopped */
320 clear_share_rules (req);
324 nm_act_request_get_shared (NMActRequest *req)
326 g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
328 return NM_ACT_REQUEST_GET_PRIVATE (req)->shared;
332 nm_act_request_add_share_rule (NMActRequest *req,
334 const char *table_rule)
336 NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req);
339 g_return_if_fail (NM_IS_ACT_REQUEST (req));
340 g_return_if_fail (table != NULL);
341 g_return_if_fail (table_rule != NULL);
343 rule = g_malloc0 (sizeof (ShareRule));
344 rule->table = g_strdup (table);
345 rule->rule = g_strdup (table_rule);
346 priv->share_rules = g_slist_prepend (priv->share_rules, rule);
349 /********************************************************************/
352 device_notify (GObject *object,
356 g_object_notify (self, pspec->name);
360 device_state_changed (NMActiveConnection *active,
362 NMDeviceState new_state,
363 NMDeviceState old_state)
365 NMActiveConnectionState cur_ac_state = nm_active_connection_get_state (active);
366 NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
368 /* Decide which device state changes to handle when this active connection
369 * is not the device's current request. Two cases here: (a) the AC is
370 * pending and not yet active, and (b) the AC was active but the device is
371 * entering DISCONNECTED state (which clears the device's current AC before
372 * emitting the state change signal).
374 if (NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)) != active) {
375 /* Some other request is activating; this one must be pending */
376 if (new_state >= NM_DEVICE_STATE_PREPARE)
378 else if (new_state == NM_DEVICE_STATE_DISCONNECTED) {
379 /* This request hasn't started activating yet; the device is
380 * disconnecting and cleaning up a previous activation request.
382 if (cur_ac_state < NM_ACTIVE_CONNECTION_STATE_ACTIVATING)
385 /* Catch device disconnections after this request has been active */
388 /* All states < DISCONNECTED are fatal and handled */
391 /* Set NMActiveConnection state based on the device's state */
393 case NM_DEVICE_STATE_PREPARE:
394 case NM_DEVICE_STATE_CONFIG:
395 case NM_DEVICE_STATE_NEED_AUTH:
396 case NM_DEVICE_STATE_IP_CONFIG:
397 case NM_DEVICE_STATE_IP_CHECK:
398 case NM_DEVICE_STATE_SECONDARIES:
399 ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
401 case NM_DEVICE_STATE_ACTIVATED:
402 ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
404 g_signal_connect (device, "notify::" NM_DEVICE_IP4_CONFIG,
405 G_CALLBACK (device_notify), active);
406 g_signal_connect (device, "notify::" NM_DEVICE_DHCP4_CONFIG,
407 G_CALLBACK (device_notify), active);
408 g_signal_connect (device, "notify::" NM_DEVICE_IP6_CONFIG,
409 G_CALLBACK (device_notify), active);
410 g_signal_connect (device, "notify::" NM_DEVICE_DHCP6_CONFIG,
411 G_CALLBACK (device_notify), active);
413 case NM_DEVICE_STATE_DEACTIVATING:
414 ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATING;
416 case NM_DEVICE_STATE_FAILED:
417 case NM_DEVICE_STATE_DISCONNECTED:
418 case NM_DEVICE_STATE_UNMANAGED:
419 case NM_DEVICE_STATE_UNAVAILABLE:
420 ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED;
422 g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_notify), active);
428 if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
429 || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
430 nm_active_connection_set_default (active, FALSE);
431 nm_active_connection_set_default6 (active, FALSE);
434 nm_active_connection_set_state (active, ac_state);
438 master_failed (NMActiveConnection *self)
441 NMDeviceState device_state;
443 /* If the connection has an active device, fail it */
444 device = nm_active_connection_get_device (self);
446 device_state = nm_device_get_state (device);
447 if (nm_device_is_activating (device) || (device_state == NM_DEVICE_STATE_ACTIVATED)) {
448 nm_device_state_changed (device,
449 NM_DEVICE_STATE_FAILED,
450 NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
455 /* If no device, or the device wasn't active, just move to deactivated state */
456 nm_active_connection_set_state (self, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
459 /********************************************************************/
462 * nm_act_request_new:
464 * @settings_connection: (allow-none): the connection to activate @device with
465 * @specific_object: the object path of the specific object (ie, WiFi access point,
466 * etc) that will be used to activate @connection and @device
467 * @subject: the #NMAuthSubject representing the requestor of the activation
468 * @device: the device/interface to configure according to @connection
470 * Creates a new device-based activation request.
472 * Returns: the new activation request on success, %NULL on error.
475 nm_act_request_new (NMSettingsConnection *settings_connection,
476 const char *specific_object,
477 NMAuthSubject *subject,
480 g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
481 g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
482 g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
484 return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST,
485 NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, settings_connection,
486 NM_ACTIVE_CONNECTION_INT_DEVICE, device,
487 NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
488 NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
493 nm_act_request_init (NMActRequest *req)
498 dispose (GObject *object)
500 NMActRequest *self = NM_ACT_REQUEST (object);
501 NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
503 /* Kill any in-progress secrets requests */
504 while (priv->secrets_calls)
505 _do_cancel_secrets (self, priv->secrets_calls->data, TRUE);
507 /* Clear any share rules */
508 if (priv->share_rules) {
509 nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE);
510 clear_share_rules (NM_ACT_REQUEST (object));
513 G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
517 get_property (GObject *object, guint prop_id,
518 GValue *value, GParamSpec *pspec)
522 device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
524 g_value_set_string (value, "/");
529 case PROP_IP4_CONFIG:
530 g_object_get_property (G_OBJECT (device), NM_DEVICE_IP4_CONFIG, value);
532 case PROP_DHCP4_CONFIG:
533 g_object_get_property (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG, value);
535 case PROP_IP6_CONFIG:
536 g_object_get_property (G_OBJECT (device), NM_DEVICE_IP6_CONFIG, value);
538 case PROP_DHCP6_CONFIG:
539 g_object_get_property (G_OBJECT (device), NM_DEVICE_DHCP6_CONFIG, value);
542 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
548 nm_act_request_class_init (NMActRequestClass *req_class)
550 GObjectClass *object_class = G_OBJECT_CLASS (req_class);
551 NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (req_class);
553 g_type_class_add_private (req_class, sizeof (NMActRequestPrivate));
555 /* virtual methods */
556 object_class->dispose = dispose;
557 object_class->get_property = get_property;
558 active_class->master_failed = master_failed;
559 active_class->device_state_changed = device_state_changed;
562 g_object_class_override_property (object_class, PROP_IP4_CONFIG,
563 NM_ACTIVE_CONNECTION_IP4_CONFIG);
564 g_object_class_override_property (object_class, PROP_DHCP4_CONFIG,
565 NM_ACTIVE_CONNECTION_DHCP4_CONFIG);
566 g_object_class_override_property (object_class, PROP_IP6_CONFIG,
567 NM_ACTIVE_CONNECTION_IP6_CONFIG);
568 g_object_class_override_property (object_class, PROP_DHCP6_CONFIG,
569 NM_ACTIVE_CONNECTION_DHCP6_CONFIG);