static gboolean _netns_switch_push (NMPNetns *self, int ns_types) { int errsv; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) && !_stack_current_ns_types (self, CLONE_NEWNET) && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); return FALSE; } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) && !_stack_current_ns_types (self, CLONE_NEWNS) && _setns (self, CLONE_NEWNS) != 0) { errsv = errno; _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); /* try to fix the mess by returning to the previous netns. */ if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) && !_stack_current_ns_types (self, CLONE_NEWNET)) { self = _stack_current_netns (CLONE_NEWNET); if ( self && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; _LOGE (self, "failed to restore netns: %s", g_strerror (errsv)); } } return FALSE; } return TRUE; }
static gboolean _netns_switch_pop (NMPNetns *self, int ns_types) { int errsv; NMPNetns *current; int success = TRUE; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) && (!self || !_stack_current_ns_types (self, CLONE_NEWNET))) { current = _stack_current_netns (CLONE_NEWNET); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNET) != 0) { errsv = errno; _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); success = FALSE; } } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) && (!self || !_stack_current_ns_types (self, CLONE_NEWNS))) { current = _stack_current_netns (CLONE_NEWNS); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNS) != 0) { errsv = errno; _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); success = FALSE; } } return success; }
static int _stack_current_ns_types (NMPNetns *netns, int ns_types) { const int ns_types_check[] = { _CLONE_NS_ALL_V }; guint i, j; int res = 0; nm_assert (netns); nm_assert (netns_stack && netns_stack->len > 0); /* we search the stack top-down to check which of @ns_types * are already set to @netns. */ for (j = netns_stack->len; ns_types && j >= 1; ) { NetnsInfo *info; info = &g_array_index (netns_stack, NetnsInfo, --j); if (info->netns != netns) { ns_types = NM_FLAGS_UNSET (ns_types, info->ns_types); continue; } for (i = 0; i < G_N_ELEMENTS (ns_types_check); i++) { if ( NM_FLAGS_HAS (ns_types, ns_types_check[i]) && NM_FLAGS_HAS (info->ns_types, ns_types_check[i])) { res = NM_FLAGS_SET (res, ns_types_check[i]); ns_types = NM_FLAGS_UNSET (ns_types, ns_types_check[i]); } } } return res; }
static void _init_nm_debug (const char *debug) { const guint D_RLIMIT_CORE = 1; const guint D_FATAL_WARNINGS = 2; GDebugKey keys[] = { { "RLIMIT_CORE", D_RLIMIT_CORE }, { "fatal-warnings", D_FATAL_WARNINGS }, }; guint flags = 0; const char *env = getenv ("NM_DEBUG"); if (env && strcasecmp (env, "help") != 0) { /* g_parse_debug_string() prints options to stderr if the variable * is set to "help". Don't allow that. */ flags = g_parse_debug_string (env, keys, G_N_ELEMENTS (keys)); } if (debug && strcasecmp (debug, "help") != 0) flags |= g_parse_debug_string (debug, keys, G_N_ELEMENTS (keys)); if (NM_FLAGS_HAS (flags, D_RLIMIT_CORE)) { /* only enable this, if explicitly requested, because it might * expose sensitive data. */ struct rlimit limit = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY, }; setrlimit (RLIMIT_CORE, &limit); } if (NM_FLAGS_HAS (flags, D_FATAL_WARNINGS)) _set_g_fatal_warnings (); }
static void _init_nm_debug (const char *debug) { const guint D_RLIMIT_CORE = 1; const guint D_FATAL_WARNINGS = 2; GDebugKey keys[] = { { "RLIMIT_CORE", D_RLIMIT_CORE }, { "fatal-warnings", D_FATAL_WARNINGS }, }; guint flags; const char *env = getenv ("NM_DEBUG"); flags = nm_utils_parse_debug_string (env, keys, G_N_ELEMENTS (keys)); flags |= nm_utils_parse_debug_string (debug, keys, G_N_ELEMENTS (keys)); if (NM_FLAGS_HAS (flags, D_RLIMIT_CORE)) { /* only enable this, if explicitly requested, because it might * expose sensitive data. */ struct rlimit limit = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY, }; setrlimit (RLIMIT_CORE, &limit); } if (NM_FLAGS_HAS (flags, D_FATAL_WARNINGS)) _set_g_fatal_warnings (); }
static void config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMAuditManager *self) { if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) init_auditd (self); }
gboolean _nm_setting_bond_option_supported (const char *option, NMBondMode mode) { guint i; for (i = 0; i < G_N_ELEMENTS (bond_unsupp_modes); i++) { if (nm_streq (option, bond_unsupp_modes[i].option)) return !NM_FLAGS_HAS (bond_unsupp_modes[i].unsupp_modes, BIT (mode)); } return TRUE; }
NMConnection * nm_keyfile_plugin_connection_from_file (const char *filename, GError **error) { GKeyFile *key_file; struct stat statbuf; NMConnection *connection = NULL; GError *verify_error = NULL; if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "File did not exist or was not a regular file"); return NULL; } if (statbuf.st_mode & 0077) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "File permissions (%o) were insecure", statbuf.st_mode); return NULL; } if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) { if (statbuf.st_uid != 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "File owner (%o) is insecure", statbuf.st_mode); return NULL; } } key_file = g_key_file_new (); if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) goto out; connection = nm_keyfile_read (key_file, filename, NULL, _handler_read, NULL, error); if (!connection) goto out; /* Normalize and verify the connection */ if (!nm_connection_normalize (connection, NULL, NULL, &verify_error)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid connection: %s", verify_error->message); g_clear_error (&verify_error); g_object_unref (connection); connection = NULL; } out: g_key_file_free (key_file); return connection; }
static char * build_message (GPtrArray *fields, AuditBackend backend) { GString *string; AuditField *field; gboolean first = TRUE; guint i; string = g_string_new (NULL); for (i = 0; i < fields->len; i++) { field = fields->pdata[i]; if (!NM_FLAGS_HAS (field->backends, backend)) continue; if (first) first = FALSE; else g_string_append_c (string, ' '); if (G_VALUE_HOLDS_STRING (&field->value)) { const char *str = g_value_get_string (&field->value); #if HAVE_LIBAUDIT if (backend == BACKEND_AUDITD) { if (field->need_encoding) { char *value; value = audit_encode_nv_string (field->name, str, 0); g_string_append (string, value); g_free (value); } else g_string_append_printf (string, "%s=%s", field->name, str); continue; } #endif /* HAVE_LIBAUDIT */ g_string_append_printf (string, "%s=\"%s\"", field->name, str); } else if (G_VALUE_HOLDS_UINT (&field->value)) { g_string_append_printf (string, "%s=%u", field->name, g_value_get_uint (&field->value)); } else g_assert_not_reached (); } return g_string_free (string, FALSE); }
static gboolean compare_property (NMSetting *setting, NMSetting *other, const GParamSpec *prop_spec, NMSettingCompareFlags flags) { NMSettingClass *parent_class; /* If we are trying to match a connection in order to assume it (and thus * @flags contains INFERRABLE), use the "relaxed" matching for team * configuration. Otherwise, for all other purposes (including connection * comparison before an update), resort to the default string comparison. */ if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE) && nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_CONFIG)) { return _nm_utils_team_config_equal (NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->config, NM_SETTING_TEAM_PORT_GET_PRIVATE (other)->config, TRUE); } /* Otherwise chain up to parent to handle generic compare */ parent_class = NM_SETTING_CLASS (nm_setting_team_port_parent_class); return parent_class->compare_property (setting, other, prop_spec, flags); }
gboolean nmp_utils_ethtool_set_wake_on_lan (const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password) { struct ethtool_wolinfo wol_info = { }; if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE) return TRUE; nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'", (unsigned int) wol, wol_password); wol_info.cmd = ETHTOOL_SWOL; wol_info.wolopts = 0; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY)) wol_info.wolopts |= WAKE_PHY; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST)) wol_info.wolopts |= WAKE_UCAST; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST)) wol_info.wolopts |= WAKE_MCAST; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST)) wol_info.wolopts |= WAKE_BCAST; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP)) wol_info.wolopts |= WAKE_ARP; if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) wol_info.wolopts |= WAKE_MAGIC; if (wol_password) { if (!nm_utils_hwaddr_aton (wol_password, wol_info.sopass, ETH_ALEN)) { nm_log_dbg (LOGD_PLATFORM, "couldn't parse Wake-on-LAN password '%s'", wol_password); return FALSE; } wol_info.wolopts |= WAKE_MAGICSECURE; } return ethtool_get (ifname, &wol_info); }
static void update_properties_from_ifindex (NMDevice *device, int ifindex) { NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); GObject *object = G_OBJECT (device); NMDevice *parent; int parent_ifindex; in_addr_t local4, remote4; struct in6_addr local6, remote6; guint8 ttl = 0, tos = 0, encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; char *key; if (ifindex <= 0) { clear: if (priv->parent || priv->parent_ifindex) { g_clear_object (&priv->parent); priv->parent_ifindex = 0; g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); } if (priv->local) { g_clear_pointer (&priv->local, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (priv->remote) { g_clear_pointer (&priv->remote, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } if (priv->input_key) { g_clear_pointer (&priv->input_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } if (priv->output_key) { g_clear_pointer (&priv->output_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } goto out; } if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { const NMPlatformLnkGre *lnk; lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "gre"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) { key = g_strdup_printf ("%u", lnk->input_key); if (g_strcmp0 (priv->input_key, key)) { g_free (priv->input_key); priv->input_key = key; g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } else g_free (key); } else { if (priv->input_key) { g_clear_pointer (&priv->input_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); } } if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) { key = g_strdup_printf ("%u", lnk->output_key); if (g_strcmp0 (priv->output_key, key)) { g_free (priv->output_key); priv->output_key = key; g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } else g_free (key); } else { if (priv->output_key) { g_clear_pointer (&priv->output_key, g_free); g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); } } } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { const NMPlatformLnkSit *lnk; lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "sit"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { const NMPlatformLnkIpIp *lnk; lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "ipip"); goto clear; } parent_ifindex = lnk->parent_ifindex; local4 = lnk->local; remote4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { const NMPlatformLnkIp6Tnl *lnk; lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL); if (!lnk) { _LOGW (LOGD_HW, "could not read %s properties", "ip6tnl"); goto clear; } parent_ifindex = lnk->parent_ifindex; local6 = lnk->local; remote6 = lnk->remote; ttl = lnk->ttl; tos = lnk->tclass; encap_limit = lnk->encap_limit; flow_label = lnk->flow_label; } else g_return_if_reached (); if (priv->parent_ifindex != parent_ifindex) { g_clear_object (&priv->parent); priv->parent_ifindex = parent_ifindex; parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); if (parent) priv->parent = g_object_ref (parent); g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); } if (priv->addr_family == AF_INET) { if (!address_equal_pn (AF_INET, priv->local, &local4)) { g_clear_pointer (&priv->local, g_free); if (local4) priv->local = g_strdup (nm_utils_inet4_ntop (local4, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (!address_equal_pn (AF_INET, priv->remote, &remote4)) { g_clear_pointer (&priv->remote, g_free); if (remote4) priv->remote = g_strdup (nm_utils_inet4_ntop (remote4, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } } else { if (!address_equal_pn (AF_INET6, priv->local, &local6)) { g_clear_pointer (&priv->local, g_free); if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any))) priv->local = g_strdup (nm_utils_inet6_ntop (&local6, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); } if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) { g_clear_pointer (&priv->remote, g_free); if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any))) priv->remote = g_strdup (nm_utils_inet6_ntop (&remote6, NULL)); g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); } } out: if (priv->ttl != ttl) { priv->ttl = ttl; g_object_notify (object, NM_DEVICE_IP_TUNNEL_TTL); } if (priv->tos != tos) { priv->tos = tos; g_object_notify (object, NM_DEVICE_IP_TUNNEL_TOS); } if (priv->path_mtu_discovery != pmtud) { priv->path_mtu_discovery = pmtud; g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY); } if (priv->encap_limit != encap_limit) { priv->encap_limit = encap_limit; g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT); } if (priv->flow_label != flow_label) { priv->flow_label = flow_label; g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL); } }
NMCheckpoint * nm_checkpoint_manager_create (NMCheckpointManager *self, const char *const *device_paths, guint32 rollback_timeout, NMCheckpointCreateFlags flags, GError **error) { NMManager *manager; NMCheckpoint *checkpoint; const char * const *path; gs_unref_ptrarray GPtrArray *devices = NULL; NMDevice *device; const char *checkpoint_path; gs_free const char **device_paths_free = NULL; guint i; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (!error || !*error, FALSE); manager = GET_MANAGER (self); if (!device_paths || !device_paths[0]) { device_paths_free = nm_manager_get_device_paths (manager); device_paths = (const char *const *) device_paths_free; } else if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, "the DISCONNECT_NEW_DEVICES flag can only be used with an empty device list"); return NULL; } devices = g_ptr_array_new (); for (path = device_paths; *path; path++) { device = nm_manager_get_device_by_path (manager, *path); if (!device) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "device %s does not exist", *path); return NULL; } g_ptr_array_add (devices, device); } if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) { for (i = 0; i < devices->len; i++) { device = devices->pdata[i]; if (find_checkpoint_for_device (self, device)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, "a checkpoint for device '%s' already exists", nm_device_get_iface (device)); return NULL; } } } checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags, error); if (!checkpoint) return NULL; if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) g_hash_table_remove_all (self->checkpoints); nm_exported_object_export (NM_EXPORTED_OBJECT (checkpoint)); checkpoint_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint)); if (!nm_g_hash_table_insert (self->checkpoints, (gpointer) checkpoint_path, checkpoint)) g_return_val_if_reached (NULL); update_rollback_timeout (self); return checkpoint; }