diff --git a/ChangeLog b/ChangeLog index 4cf89d6ec..accf9deed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-04-15 Dan Williams + + Initial VPN Support + - supports 'vpnc' + - reworks device IP configuration, backend files have changed and will need + to be updated for all distributions. I will try to do what I can for + them, but I cannot test them. + + - Move named directory to src/named-manager + - Make backends directory self-contained + 2005-04-06 Dan Williams Add debug code for socket/file descriptor leaks. We register every socket diff --git a/Makefile.am b/Makefile.am index 6b6dbda57..15231ac48 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = utils dhcpcd named src libnm_glib dispatcher-daemon $(notification_icon_dir) info-daemon initscript test po +SUBDIRS = utils dhcpcd src libnm_glib dispatcher-daemon $(notification_icon_dir) info-daemon vpn-daemons initscript test po EXTRA_DIST = CONTRIBUTING NetworkManager.pc.in NetworkManager.h diff --git a/NetworkManager.h b/NetworkManager.h index 06cdfc3cb..66aa3797b 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -33,6 +33,8 @@ #define NM_DBUS_INTERFACE_DEVICES "org.freedesktop.NetworkManager.Devices" #define NM_DBUS_PATH_DHCP "/org/freedesktop/NetworkManager/DhcpOptions" #define NM_DBUS_INTERFACE_DHCP "org.freedesktop.NetworkManager.DhcpOptions" +#define NM_DBUS_PATH_VPN "/org/freedesktop/NetworkManager/VPNConnections" +#define NM_DBUS_INTERFACE_VPN "org.freedesktop.NetworkManager.VPNConnections" #define NMI_DBUS_SERVICE "org.freedesktop.NetworkManagerInfo" #define NMI_DBUS_PATH "/org/freedesktop/NetworkManagerInfo" @@ -46,6 +48,21 @@ #define NM_DBUS_NO_ACTIVE_DEVICE_ERROR "org.freedesktop.NetworkManager.NoActiveDevice" #define NM_DBUS_NO_NETWORKS_ERROR "org.freedesktop.NetworkManager.NoNetworks" +#define NM_DBUS_NO_ACTIVE_VPN_CONNECTION "org.freedesktop.NetworkManager.VPNConnections.NoActiveVPNConnection" +#define NM_DBUS_NO_VPN_CONNECTIONS "org.freedesktop.NetworkManager.VPNConnections.NoVPNConnections" + +#define NM_DBUS_VPN_STARTING_IN_PROGRESS "StartingInProgress" +#define NM_DBUS_VPN_ALREADY_STARTED "AlreadyStarted" +#define NM_DBUS_VPN_STOPPING_IN_PROGRESS "StoppingInProgress" +#define NM_DBUS_VPN_ALREADY_STOPPED "AlreadyStopped" +#define NM_DBUS_VPN_WRONG_STATE "WrongState" +#define NM_DBUS_VPN_BAD_ARGUMENTS "BadArguments" + +#define NM_DBUS_VPN_SIGNAL_LOGIN_FAILED "LoginFailed" +#define NM_DBUS_VPN_SIGNAL_CONFIG_BAD "ConfigurationBad" +#define NM_DBUS_VPN_SIGNAL_STATE_CHANGE "StateChange" +#define NM_DBUS_VPN_SIGNAL_IP4_CONFIG "IP4Config" + /* * Types of NetworkManager devices @@ -130,6 +147,21 @@ typedef enum NMDeviceAuthMethod } NMDeviceAuthMethod; +/* + * VPN daemon states + */ +typedef enum NMVPNState +{ + NM_VPN_STATE_ERROR = 0, + NM_VPN_STATE_INIT, + NM_VPN_STATE_SHUTDOWN, + NM_VPN_STATE_STARTING, + NM_VPN_STATE_STARTED, + NM_VPN_STATE_STOPPING, + NM_VPN_STATE_STOPPED +} NMVPNState; + + /* * Info-daemon specific preference locations */ diff --git a/configure.in b/configure.in index b41fa49c0..a8a8448ae 100644 --- a/configure.in +++ b/configure.in @@ -169,6 +169,10 @@ PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0) AC_SUBST(LIBGNOMEUI_CFLAGS) # is this even needed? it was typed incorrectly before AC_SUBST(LIBGNOMEUI_LIBS) +PKG_CHECK_MODULES(GNOMEKEYRING, gnome-keyring-1) +AC_SUBST(GNOMEKEYRING_CFLAGS) # is this even needed? it was typed incorrectly before +AC_SUBST(GNOMEKEYRING_LIBS) + AC_ARG_WITH(dbus-sys, AC_HELP_STRING([--with-dbus-sys=DIR], [where D-BUS system.d directory is])) if ! test -z "$with_dbus_sys" ; then @@ -266,11 +270,13 @@ AC_OUTPUT([ Makefile utils/Makefile src/Makefile +src/named-manager/Makefile +src/vpn-manager/Makefile +src/backends/Makefile dispatcher-daemon/Makefile info-daemon/Makefile panel-applet/Makefile panel-applet/icons/Makefile -named/Makefile dhcpcd/Makefile libnm_glib/Makefile test/Makefile @@ -282,6 +288,8 @@ initscript/Slackware/Makefile po/Makefile.in NetworkManager.pc libnm_glib/libnm_glib.pc +vpn-daemons/Makefile +vpn-daemons/vpnc/Makefile ]) echo diff --git a/info-daemon/NetworkManagerInfo.c b/info-daemon/NetworkManagerInfo.c index 65e3f1b26..d8778201d 100644 --- a/info-daemon/NetworkManagerInfo.c +++ b/info-daemon/NetworkManagerInfo.c @@ -49,12 +49,12 @@ static void nmi_spawn_notification_icon (NMIAppInfo *info); /* - * nmi_gconf_notify_callback + * nmi_gconf_networks_notify_callback * * Callback from gconf when wireless networking key/values have changed. * */ -void nmi_gconf_notify_callback (GConfClient *client, guint connection_id, GConfEntry *entry, gpointer user_data) +static void nmi_gconf_networks_notify_callback (GConfClient *client, guint connection_id, GConfEntry *entry, gpointer user_data) { NMIAppInfo *info = (NMIAppInfo *)user_data; const char *key = NULL; @@ -88,6 +88,46 @@ void nmi_gconf_notify_callback (GConfClient *client, guint connection_id, GConfE } +/* + * nmi_gconf_vpn_connections_notify_callback + * + * Callback from gconf when VPN connection values have changed. + * + */ +static void nmi_gconf_vpn_connections_notify_callback (GConfClient *client, guint connection_id, GConfEntry *entry, gpointer user_data) +{ + NMIAppInfo *info = (NMIAppInfo *)user_data; + const char *key = NULL; + + g_return_if_fail (client != NULL); + g_return_if_fail (entry != NULL); + g_return_if_fail (info != NULL); + + if ((key = gconf_entry_get_key (entry))) + { + int path_len = strlen (NMI_GCONF_VPN_CONNECTIONS_PATH) + 1; + + if (strncmp (NMI_GCONF_VPN_CONNECTIONS_PATH"/", key, path_len) == 0) + { + char *name = g_strdup ((key + path_len)); + char *slash_pos; + char *unescaped_name; + + /* If its a key under the the VPN name, zero out the slash so we + * are left with only the VPN name. + */ + unescaped_name = gconf_unescape_key (name, strlen (name)); + if ((slash_pos = strchr (unescaped_name, '/'))) + *slash_pos = '\0'; + + nmi_dbus_signal_update_vpn_connection (info->connection, unescaped_name); + g_free (unescaped_name); + g_free (name); + } + } +} + + #ifdef BUILD_NOTIFICATION_ICON static void on_icon_exit_callback (GPid pid, int status, gpointer data) @@ -238,7 +278,9 @@ int main( int argc, char *argv[] ) gconf_client_add_dir (app_info->gconf_client, NMI_GCONF_WIRELESS_NETWORKS_PATH, GCONF_CLIENT_PRELOAD_NONE, NULL); notify_id = gconf_client_notify_add (app_info->gconf_client, NMI_GCONF_WIRELESS_NETWORKS_PATH, - nmi_gconf_notify_callback, app_info, NULL, NULL); + nmi_gconf_networks_notify_callback, app_info, NULL, NULL); + notify_id = gconf_client_notify_add (app_info->gconf_client, NMI_GCONF_VPN_CONNECTIONS_PATH, + nmi_gconf_vpn_connections_notify_callback, app_info, NULL, NULL); /* Create our own dbus service */ err = nmi_dbus_service_init (dbus_connection, app_info); diff --git a/info-daemon/NetworkManagerInfo.h b/info-daemon/NetworkManagerInfo.h index 4b1845a10..3c3be1fbb 100644 --- a/info-daemon/NetworkManagerInfo.h +++ b/info-daemon/NetworkManagerInfo.h @@ -32,6 +32,8 @@ #include #include +#define NMI_GCONF_VPN_CONNECTIONS_PATH "/system/networking/vpn_connections" + struct NMIAppInfo { GladeXML *passphrase_dialog; diff --git a/info-daemon/NetworkManagerInfoDbus.c b/info-daemon/NetworkManagerInfoDbus.c index 1958b305e..ae82e8621 100644 --- a/info-daemon/NetworkManagerInfoDbus.c +++ b/info-daemon/NetworkManagerInfoDbus.c @@ -35,7 +35,6 @@ #include "NetworkManagerInfoVPN.h" #include "nm-utils.h" - /* * nmi_show_warning_dialog * @@ -332,7 +331,7 @@ static DBusMessage *nmi_dbus_get_networks (NMIAppInfo *info, DBusMessage *messag /* - * nmi_dbus_get_network + * nmi_dbus_get_network_properties * * Returns the properties of a specific wireless network from gconf * @@ -499,6 +498,279 @@ static DBusMessage *nmi_dbus_get_network_properties (NMIAppInfo *info, DBusMessa } +/* + * nmi_dbus_signal_update_vpn_connection + * + * Signal NetworkManager that it needs to update info associated with a particular + * VPN connection. + * + */ +void nmi_dbus_signal_update_vpn_connection (DBusConnection *connection, const char *name) +{ + DBusMessage *message; + + g_return_if_fail (connection != NULL); + g_return_if_fail (name != NULL); + + if (!(message = dbus_message_new_signal (NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "VPNConnectionUpdate"))) + { + nm_warning ("nmi_dbus_signal_update_vpn_connection(): Not enough memory for new dbus message!"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + if (!dbus_connection_send (connection, message, NULL)) + nm_warning ("nmi_dbus_signal_update_vpn_connection(): Could not raise the 'VPNConnectionUpdate' signal!"); + + dbus_message_unref (message); +} + + +/* + * nmi_dbus_get_vpn_connections + * + * Grab a list of VPN connections from GConf and return it in the form + * of a string array in a dbus message. + * + */ +static DBusMessage *nmi_dbus_get_vpn_connections (NMIAppInfo *info, DBusMessage *message) +{ + GSList *dir_list = NULL; + GSList *element = NULL; + DBusError error; + DBusMessage *reply_message = NULL; + DBusMessageIter iter; + DBusMessageIter iter_array; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + dbus_error_init (&error); + + /* List all VPN connections that gconf knows about */ + element = dir_list = gconf_client_all_dirs (info->gconf_client, NMI_GCONF_VPN_CONNECTIONS_PATH, NULL); + if (!dir_list) + { + reply_message = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "NoVPNConnections", + "There are no VPN connections stored."); + } + else + { + gboolean value_added = FALSE; + + reply_message = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply_message, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); + + /* Append the essid of every allowed or ignored access point we know of + * to a string array in the dbus message. + */ + while (element) + { + char key[100]; + GConfValue *value; + + g_snprintf (&key[0], 99, "%s/name", (char *)(element->data)); + value = gconf_client_get (info->gconf_client, key, NULL); + if (value && gconf_value_get_string (value)) + { + const gchar *essid; + essid = gconf_value_get_string (value); + dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &essid); + value_added = TRUE; + gconf_value_free (value); + } + + g_free (element->data); + element = element->next; + } + g_slist_free (dir_list); + + dbus_message_iter_close_container (&iter, &iter_array); + + if (!value_added) + { + dbus_message_unref (reply_message); + reply_message = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "NoVPNConnections", + "There are no VPN connections stored."); + } + } + + return (reply_message); +} + + +/* + * nmi_dbus_get_vpn_connection_properties + * + * Returns the properties of a specific VPN connection from gconf + * + */ +static DBusMessage *nmi_dbus_get_vpn_connection_properties (NMIAppInfo *info, DBusMessage *message) +{ + DBusMessage *reply = NULL; + gchar *gconf_key = NULL; + char *vpn_connection = NULL; + GConfValue *value; + DBusError error; + char *escaped_name; + char *name = NULL; + char *service_name = NULL; + char *user_name = NULL; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + dbus_error_init (&error); + if ( !dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &vpn_connection, DBUS_TYPE_INVALID) + || (strlen (vpn_connection) <= 0)) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "InvalidArguments", + "NetworkManagerInfo::getVPNConnectionProperties called with invalid arguments."); + return (reply); + } + + escaped_name = gconf_escape_key (vpn_connection, strlen (vpn_connection)); + + /* User-visible name of connection */ + gconf_key = g_strdup_printf ("%s/%s/name", NMI_GCONF_VPN_CONNECTIONS_PATH, escaped_name); + if ((value = gconf_client_get (info->gconf_client, gconf_key, NULL))) + { + name = g_strdup (gconf_value_get_string (value)); + gconf_value_free (value); + } + g_free (gconf_key); + + /* Service name of connection */ + gconf_key = g_strdup_printf ("%s/%s/service_name", NMI_GCONF_VPN_CONNECTIONS_PATH, escaped_name); + if ((value = gconf_client_get (info->gconf_client, gconf_key, NULL))) + { + service_name = g_strdup (gconf_value_get_string (value)); + gconf_value_free (value); + } + g_free (gconf_key); + + /* User name of connection */ + gconf_key = g_strdup_printf ("%s/%s/user_name", NMI_GCONF_VPN_CONNECTIONS_PATH, escaped_name); + if ((value = gconf_client_get (info->gconf_client, gconf_key, NULL))) + { + user_name = g_strdup (gconf_value_get_string (value)); + gconf_value_free (value); + } + g_free (gconf_key); + + if (!name) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", + "NetworkManagerInfo::getVPNConnectionProperties could not access the name for connection '%s'", vpn_connection); + } + else if (!service_name) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", + "NetworkManagerInfo::getVPNConnectionProperties could not access the service name for connection '%s'", vpn_connection); + } + else if (!user_name) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", + "NetworkManagerInfo::getVPNConnectionProperties could not access the user name for connection '%s'", vpn_connection); + } + else + { + DBusMessageIter iter, array_iter; + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &service_name); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &user_name); + } + + g_free (user_name); + g_free (service_name); + g_free (name); + g_free (escaped_name); + + return (reply); +} + + +/* + * nmi_dbus_get_vpn_connection_vpn_data + * + * Returns vpn-daemon specific properties for a particular VPN connection. + * + */ +static DBusMessage *nmi_dbus_get_vpn_connection_vpn_data (NMIAppInfo *info, DBusMessage *message) +{ + DBusMessage *reply = NULL; + gchar *gconf_key = NULL; + char *name = NULL; + GConfValue *vpn_data_value = NULL; + GConfValue *value = NULL; + DBusError error; + char *escaped_name; + DBusMessageIter iter, array_iter; + GSList *elt; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + dbus_error_init (&error); + if ( !dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID) + || (strlen (name) <= 0)) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "InvalidArguments", + "NetworkManagerInfo::getVPNConnectionVPNData called with invalid arguments."); + return reply; + } + + escaped_name = gconf_escape_key (name, strlen (name)); + + /* User-visible name of connection */ + gconf_key = g_strdup_printf ("%s/%s/name", NMI_GCONF_VPN_CONNECTIONS_PATH, escaped_name); + if (!(value = gconf_client_get (info->gconf_client, gconf_key, NULL))) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", + "NetworkManagerInfo::getVPNConnectionVPNData could not access the name for connection '%s'", name); + return reply; + } + gconf_value_free (value); + g_free (gconf_key); + + /* Grab vpn-daemon specific data */ + gconf_key = g_strdup_printf ("%s/%s/vpn_data", NMI_GCONF_VPN_CONNECTIONS_PATH, escaped_name); + if (!(vpn_data_value = gconf_client_get (info->gconf_client, gconf_key, NULL)) + || !(vpn_data_value->type == GCONF_VALUE_LIST) + || !(gconf_value_get_list_type (vpn_data_value) == GCONF_VALUE_STRING)) + { + reply = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", + "NetworkManagerInfo::getVPNConnectionVPNData could not access the VPN data for connection '%s'", name); + if (vpn_data_value) + gconf_value_free (vpn_data_value); + return reply; + } + g_free (gconf_key); + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter); + + for (elt = gconf_value_get_list (vpn_data_value); elt; elt = g_slist_next (elt)) + { + const char *string = gconf_value_get_string ((GConfValue *)elt->data); + if (string) + dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &string); + } + + dbus_message_iter_close_container (&iter, &array_iter); + + gconf_value_free (vpn_data_value); + g_free (escaped_name); + + return (reply); +} + + /* * nmi_dbus_update_network_auth_method * @@ -707,6 +979,12 @@ static DBusHandlerResult nmi_dbus_nmi_message_handler (DBusConnection *connectio nmi_dbus_update_network_auth_method (info, message); else if (strcmp ("addNetworkAddress", method) == 0) nmi_dbus_add_network_address (info, message); + else if (strcmp ("getVPNConnections", method) == 0) + reply_message = nmi_dbus_get_vpn_connections (info, message); + else if (strcmp ("getVPNConnectionProperties", method) == 0) + reply_message = nmi_dbus_get_vpn_connection_properties (info, message); + else if (strcmp ("getVPNConnectionVPNData", method) == 0) + reply_message = nmi_dbus_get_vpn_connection_vpn_data (info, message); else { reply_message = nmi_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "UnknownMethod", diff --git a/info-daemon/NetworkManagerInfoDbus.h b/info-daemon/NetworkManagerInfoDbus.h index 423ca44be..2de90e35a 100644 --- a/info-daemon/NetworkManagerInfoDbus.h +++ b/info-daemon/NetworkManagerInfoDbus.h @@ -43,4 +43,6 @@ void nmi_dbus_return_vpn_password (DBusConnection *connection, DBusMessage *me void nmi_dbus_signal_update_network (DBusConnection *connection, const char *network, NMNetworkType type); +void nmi_dbus_signal_update_vpn_connection (DBusConnection *connection, const char *name); + #endif diff --git a/named/Makefile.am b/named/Makefile.am deleted file mode 100644 index 7ea6d83cc..000000000 --- a/named/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ - -namedconf_DATA = named.conf -namedconfdir = $(pkgdatadir) - -EXTRA_DIST = $(namedconf_DATA) - -INCLUDES = -I${top_srcdir}/utils - -noinst_LTLIBRARIES = libnamed.la - -libnamed_la_SOURCES = nm-named-manager.h nm-named-manager.c - -libnamed_la_CPPFLAGS = $(DBUS_CFLAGS) $(GTHREAD_CFLAGS) -DNM_PKGDATADIR=\"$(pkgdatadir)\" -DNM_LOCALSTATEDIR=\"$(localstatedir)\" - -libnamed_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) diff --git a/panel-applet/Makefile.am b/panel-applet/Makefile.am index 962c3073c..b396f91b6 100644 --- a/panel-applet/Makefile.am +++ b/panel-applet/Makefile.am @@ -20,6 +20,7 @@ libnm_notification_applet_la_CPPFLAGS = \ $(GCONF_CFLAGS) \ $(LIBGNOMEUI_CFLAGS) \ $(PANEL_APPLET_CFLAGS) \ + $(GNOMEKEYRING_CFLAGS) \ -DICONDIR=\""$(datadir)/pixmaps"\" \ -DGLADEDIR=\""$(gladedir)"\" \ -DDBUS_API_SUBJECT_TO_CHANGE \ @@ -43,6 +44,10 @@ libnm_notification_applet_la_SOURCES = \ gtkcellview.h \ gtkcellrendererprogress.c \ gtkcellrendererprogress.h \ + nmwa-vpn-password-dialog.c \ + nmwa-vpn-password-dialog.h \ + nmwa-vpn-connection.c \ + nmwa-vpn-connection.h \ $(NULL) libnm_notification_applet_la_SOURCES += \ @@ -59,6 +64,7 @@ libnm_notification_applet_la_LIBADD = \ $(GTK_LIBS) \ $(GCONF_LIBS) \ $(LIBGNOMEUI_LIBS) \ + $(GNOMEKEYRING_LIBS) \ $(NULL) libexec_PROGRAMS = NetworkManagerNotification diff --git a/panel-applet/NMWirelessApplet.c b/panel-applet/NMWirelessApplet.c index cd28cfde6..1cdd584aa 100644 --- a/panel-applet/NMWirelessApplet.c +++ b/panel-applet/NMWirelessApplet.c @@ -56,6 +56,8 @@ #include "NMWirelessAppletDbus.h" #include "NMWirelessAppletOtherNetworkDialog.h" #include "menu-info.h" +#include "nmwa-vpn-password-dialog.h" +#include "nmwa-vpn-connection.h" #define CFG_UPDATE_INTERVAL 1 #define NMWA_GCONF_PATH "/apps/NetworkManagerNotification" @@ -176,6 +178,119 @@ void nmwa_about_cb (NMWirelessApplet *applet) #endif } + +static void vpn_login_failure_dialog_close_cb (GtkWidget *dialog, gpointer user_data) +{ + char *message; + + if ((message = g_object_get_data (G_OBJECT (dialog), "message"))) + { + g_object_set_data (G_OBJECT (dialog), "message", NULL); + g_free (message); + } + + gtk_widget_destroy (dialog); +} + + +/* + * nmwa_show_vpn_login_failure_dialog + * + * Present the VPN login failure dialog. + * + */ +static gboolean nmwa_show_vpn_login_failure_dialog (char *message) +{ + GtkWidget *dialog; + + g_return_val_if_fail (message != NULL, FALSE); + + dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, message, NULL); + g_signal_connect (dialog, "response", G_CALLBACK (vpn_login_failure_dialog_close_cb), NULL); + g_signal_connect (dialog, "close", G_CALLBACK (vpn_login_failure_dialog_close_cb), NULL); + g_object_set_data (G_OBJECT (dialog), "message", message); + gtk_widget_show_all (dialog); + + return FALSE; +} + + +/* + * nmwa_schedule_vpn_login_failure_dialog + * + * Schedule display of the VPN Login Failure dialog. + * + */ +void nmwa_schedule_vpn_login_failure_dialog (NMWirelessApplet *applet, const char *vpn_name, const char *error_msg) +{ + char *msg; + + g_return_if_fail (applet != NULL); + g_return_if_fail (vpn_name != NULL); + g_return_if_fail (error_msg != NULL); + + msg = g_strdup_printf (_("VPN Login Failure\n\nCould not connection to the" + "VPN connection '%s' due to a login failure.\n\nThe VPN service said: \"%s\""), vpn_name, error_msg); + g_idle_add ((GSourceFunc) nmwa_show_vpn_login_failure_dialog, msg); +} + + +static void vpn_login_banner_dialog_close_cb (GtkWidget *dialog, gpointer user_data) +{ + char *message; + + if ((message = g_object_get_data (G_OBJECT (dialog), "message"))) + { + g_object_set_data (G_OBJECT (dialog), "message", NULL); + g_free (message); + } + + gtk_widget_destroy (dialog); +} + + +/* + * nmwa_show_vpn_login_banner_dialog + * + * Present the VPN login banner dialog. + * + */ +static gboolean nmwa_show_vpn_login_banner_dialog (char *message) +{ + GtkWidget *dialog; + + g_return_val_if_fail (message != NULL, FALSE); + + dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, message, NULL); + g_signal_connect (dialog, "response", G_CALLBACK (vpn_login_failure_dialog_close_cb), NULL); + g_signal_connect (dialog, "close", G_CALLBACK (vpn_login_failure_dialog_close_cb), NULL); + g_object_set_data (G_OBJECT (dialog), "message", message); + gtk_widget_show_all (dialog); + + return FALSE; +} + + +/* + * nmwa_schedule_vpn_login_banner_dialog + * + * Schedule display of the VPN Login Banner dialog. + * + */ +void nmwa_schedule_vpn_login_banner_dialog (NMWirelessApplet *applet, const char *vpn_name, const char *banner) +{ + char *msg; + + g_return_if_fail (applet != NULL); + g_return_if_fail (vpn_name != NULL); + g_return_if_fail (banner != NULL); + + msg = g_strdup_printf (_("VPN Login Message\n\n" + "VPN connection '%s' said:\n\n\"%s\""), vpn_name, banner); + g_idle_add ((GSourceFunc) nmwa_show_vpn_login_failure_dialog, msg); +} + + /* * nmwa_driver_notify_get_ignored_list * @@ -501,6 +616,29 @@ out: } +static void nmwa_set_icon (NMWirelessApplet *applet, GdkPixbuf *new_icon) +{ + GdkPixbuf *composite; + + g_return_if_fail (applet != NULL); + g_return_if_fail (new_icon != NULL); + + composite = gdk_pixbuf_copy (new_icon); + + if (applet->gui_active_vpn) + { + int dest_x = gdk_pixbuf_get_width (new_icon) - gdk_pixbuf_get_width (applet->vpn_lock_icon); + int dest_y = gdk_pixbuf_get_height (new_icon) - gdk_pixbuf_get_height (applet->vpn_lock_icon) - 2; + + gdk_pixbuf_composite (applet->vpn_lock_icon, composite, dest_x, dest_y, gdk_pixbuf_get_width (applet->vpn_lock_icon), + gdk_pixbuf_get_height (applet->vpn_lock_icon), dest_x, dest_y, 1.0, 1.0, GDK_INTERP_NEAREST, 255); + } + + gtk_image_set_from_pixbuf (GTK_IMAGE (applet->pixmap), composite); + g_object_unref (composite); +} + + static gboolean animation_timeout (NMWirelessApplet *applet) { @@ -509,16 +647,14 @@ animation_timeout (NMWirelessApplet *applet) case (APPLET_STATE_WIRED_CONNECTING): if (applet->animation_step >= NUM_WIRED_CONNECTING_FRAMES) applet->animation_step = 0; - gtk_image_set_from_pixbuf (GTK_IMAGE (applet->pixmap), - applet->wired_connecting_icons[applet->animation_step]); + nmwa_set_icon (applet, applet->wired_connecting_icons[applet->animation_step]); applet->animation_step ++; break; case (APPLET_STATE_WIRELESS_CONNECTING): if (applet->animation_step >= NUM_WIRELESS_CONNECTING_FRAMES) applet->animation_step = 0; - gtk_image_set_from_pixbuf (GTK_IMAGE (applet->pixmap), - applet->wireless_connecting_icons[applet->animation_step]); + nmwa_set_icon (applet, applet->wireless_connecting_icons[applet->animation_step]); applet->animation_step ++; break; @@ -529,8 +665,7 @@ animation_timeout (NMWirelessApplet *applet) case (APPLET_STATE_WIRELESS_SCANNING): if (applet->animation_step >= NUM_WIRELESS_SCANNING_FRAMES) applet->animation_step = 0; - gtk_image_set_from_pixbuf (GTK_IMAGE (applet->pixmap), - applet->wireless_scanning_icons[applet->animation_step]); + nmwa_set_icon (applet, applet->wireless_scanning_icons[applet->animation_step]); applet->animation_step ++; break; @@ -580,11 +715,11 @@ inline void print_state (AppletState state) * and what our icon on the panel should look like for each type. * */ -static void -nmwa_update_state (NMWirelessApplet *applet) +static void nmwa_update_state (NMWirelessApplet *applet) { gboolean show_applet = TRUE; gboolean need_animation = FALSE; + gboolean active_vpn = FALSE; GdkPixbuf *pixbuf = NULL; gint strength = -1; char *tip = NULL; @@ -702,7 +837,7 @@ nmwa_update_state (NMWirelessApplet *applet) if (need_animation) applet->animation_id = g_timeout_add (100, (GSourceFunc) (animation_timeout), applet); else - gtk_image_set_from_pixbuf (GTK_IMAGE (applet->pixmap), pixbuf); + nmwa_set_icon (applet, pixbuf); } @@ -950,6 +1085,55 @@ static void nmwa_menu_item_activate (GtkMenuItem *item, gpointer user_data) } +/* + * nmwa_menu_vpn_item_activate + * + * Signal function called when user clicks on a VPN menu item + * + */ +static void nmwa_menu_vpn_item_activate (GtkMenuItem *item, gpointer user_data) +{ + NMWirelessApplet *applet = (NMWirelessApplet *)user_data; + char *tag; + + g_return_if_fail (item != NULL); + g_return_if_fail (applet != NULL); + + if ((tag = g_object_get_data (G_OBJECT (item), "vpn"))) + { + VPNConnection *vpn = (VPNConnection *)tag; + const char *name = nmwa_vpn_connection_get_name (vpn); + char *password = NULL; + + if (vpn != applet->gui_active_vpn) + { + if ((password = nmwa_vpn_request_password (applet, name, nmwa_vpn_connection_get_user_name (vpn), FALSE))) + { + nmwa_dbus_vpn_activate_connection (applet->connection, name, password); + g_free (password); + } + } + } +} + + +/* + * nmwa_menu_disconnect_vpn_item_activate + * + * Signal function called when user clicks on a VPN menu item + * + */ +static void nmwa_menu_disconnect_vpn_item_activate (GtkMenuItem *item, gpointer user_data) +{ + NMWirelessApplet *applet = (NMWirelessApplet *)user_data; + + g_return_if_fail (item != NULL); + g_return_if_fail (applet != NULL); + + nmwa_dbus_vpn_deactivate_connection (applet->connection); +} + + /* * nmwa_menu_add_separator_item * @@ -1117,13 +1301,62 @@ static void nmwa_menu_device_add_networks (GtkWidget *menu, NetworkDevice *dev, g_object_set_data (G_OBJECT (gtk_item), "network", g_strdup (net->essid)); g_object_set_data (G_OBJECT (gtk_item), "nm_device", g_strdup (dev->nm_device)); g_object_set_data (G_OBJECT (gtk_item), "nm-item-data", item); - g_signal_connect(G_OBJECT (gtk_item), "activate", G_CALLBACK (nmwa_menu_item_activate), applet); + g_signal_connect (G_OBJECT (gtk_item), "activate", G_CALLBACK (nmwa_menu_item_activate), applet); gtk_widget_show (GTK_WIDGET (gtk_item)); } } +/* + * nmwa_menu_add_devices + * + */ +static void nmwa_menu_add_vpn_menu (GtkWidget *menu, NMWirelessApplet *applet) +{ + GtkMenuItem *item; + GtkMenu *vpn_menu; + GtkMenuItem *other_item; + GSList *elt; + + g_return_if_fail (menu != NULL); + g_return_if_fail (applet != NULL); + + item = GTK_MENU_ITEM (gtk_menu_item_new_with_label (_("VPN Connections"))); + + vpn_menu = GTK_MENU (gtk_menu_new ()); + for (elt = applet->gui_vpn_connections; elt; elt = g_slist_next (elt)) + { + GtkCheckMenuItem *vpn_item; + VPNConnection *vpn = elt->data; + const char *vpn_name = nmwa_vpn_connection_get_name (vpn); + + vpn_item = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_label (vpn_name)); + nmwa_vpn_connection_ref (vpn, __FUNCTION__); + g_object_set_data (G_OBJECT (vpn_item), "vpn", vpn); + + if (applet->gui_active_vpn && (strcmp (vpn_name, nmwa_vpn_connection_get_name (applet->gui_active_vpn)) == 0)) + gtk_check_menu_item_set_active (vpn_item, TRUE); + + g_signal_connect (G_OBJECT (vpn_item), "activate", G_CALLBACK (nmwa_menu_vpn_item_activate), applet); + gtk_menu_shell_append (GTK_MENU_SHELL (vpn_menu), GTK_WIDGET (vpn_item)); + } + other_item = GTK_MENU_ITEM (gtk_separator_menu_item_new ()); + gtk_menu_shell_append (GTK_MENU_SHELL (vpn_menu), GTK_WIDGET (other_item)); + + other_item = GTK_MENU_ITEM (gtk_menu_item_new_with_label (_("Disconnect VPN..."))); + g_signal_connect (G_OBJECT (other_item), "activate", G_CALLBACK (nmwa_menu_disconnect_vpn_item_activate), applet); + if (!applet->gui_active_vpn) + gtk_widget_set_sensitive (GTK_WIDGET (other_item), FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (vpn_menu), GTK_WIDGET (other_item)); + + gtk_menu_item_set_submenu (item, GTK_WIDGET (vpn_menu)); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item)); + gtk_widget_show_all (GTK_WIDGET (item)); +} + + /* * nmwa_menu_add_devices * @@ -1184,6 +1417,9 @@ static void nmwa_menu_add_devices (GtkWidget *menu, NMWirelessApplet *applet) } } + nmwa_menu_add_separator_item (menu); + nmwa_menu_add_vpn_menu (menu, applet); + if (n_wireless_interfaces > 0) { /* Add the "Other wireless network..." entry */ @@ -1220,13 +1456,11 @@ static void nmwa_set_wireless_enabled_cb (GtkWidget *widget, NMWirelessApplet *a static void nmwa_menu_item_data_free (GtkWidget *menu_item, gpointer data) { char *tag; - GtkWidget *menu; + GtkMenu *menu; g_return_if_fail (menu_item != NULL); g_return_if_fail (data != NULL); - menu = GTK_WIDGET(data); - if ((tag = g_object_get_data (G_OBJECT (menu_item), "network"))) { g_object_set_data (G_OBJECT (menu_item), "network", NULL); @@ -1251,6 +1485,21 @@ static void nmwa_menu_item_data_free (GtkWidget *menu_item, gpointer data) g_free (tag); } + if ((tag = g_object_get_data (G_OBJECT (menu_item), "vpn"))) + { + g_object_set_data (G_OBJECT (menu_item), "vpn", NULL); + nmwa_vpn_connection_unref ((VPNConnection *)tag, __FUNCTION__); + } + + if ((tag = g_object_get_data (G_OBJECT (menu_item), "disconnect"))) + { + g_object_set_data (G_OBJECT (menu_item), "disconnect", NULL); + g_free (tag); + } + + if ((menu = GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item))))) + gtk_container_foreach (GTK_CONTAINER (menu), nmwa_menu_item_data_free, menu); + gtk_widget_destroy (menu_item); } @@ -1665,6 +1914,7 @@ nmwa_icons_free (NMWirelessApplet *applet) g_object_unref (applet->wireless_connecting_icons[i]); for (i = 0; i < NUM_WIRELESS_SCANNING_FRAMES; i++) g_object_unref (applet->wireless_scanning_icons[i]); + g_object_unref (applet->vpn_lock_icon); } static void @@ -1720,6 +1970,7 @@ nmwa_icons_load_from_disk (NMWirelessApplet *applet, GtkIconTheme *icon_theme) applet->wireless_scanning_icons[13] = gtk_icon_theme_load_icon (icon_theme, "nm-detect14", icon_size, 0, NULL); applet->wireless_scanning_icons[14] = gtk_icon_theme_load_icon (icon_theme, "nm-detect15", icon_size, 0, NULL); applet->wireless_scanning_icons[15] = gtk_icon_theme_load_icon (icon_theme, "nm-detect16", icon_size, 0, NULL); + applet->vpn_lock_icon = gtk_icon_theme_load_icon (icon_theme, "nm-vpn-lock", icon_size, 0, NULL); } static void diff --git a/panel-applet/NMWirelessApplet.h b/panel-applet/NMWirelessApplet.h index d6d2cdd21..ad51ca2e8 100644 --- a/panel-applet/NMWirelessApplet.h +++ b/panel-applet/NMWirelessApplet.h @@ -80,6 +80,10 @@ typedef struct GSList *networks; } NetworkDevice; + +typedef struct VPNConnection VPNConnection; + + #ifdef BUILD_NOTIFICATION_ICON #define NM_TYPE_WIRELESS_APPLET (nmwa_get_type()) @@ -126,10 +130,14 @@ typedef struct GSList *gui_device_list; NetworkDevice *gui_active_device; char *gui_nm_status; + GSList *gui_vpn_connections; + VPNConnection *gui_active_vpn; GSList *dbus_device_list; NetworkDevice *dbus_active_device; char *dbus_nm_status; + GSList *dbus_vpn_connections; + VPNConnection *dbus_active_vpn; GdkPixbuf *no_nm_icon; GdkPixbuf *no_connection_icon; @@ -146,6 +154,7 @@ typedef struct GdkPixbuf *wireless_connecting_icons[NUM_WIRELESS_CONNECTING_FRAMES]; #define NUM_WIRELESS_SCANNING_FRAMES 16 GdkPixbuf *wireless_scanning_icons[NUM_WIRELESS_SCANNING_FRAMES]; + GdkPixbuf *vpn_lock_icon; /* Animation stuff */ int animation_step; @@ -155,6 +164,7 @@ typedef struct GtkWidget *pixmap; GtkWidget *top_menu_item; GtkWidget *dropdown_menu; + GtkWidget *vpn_menu; GtkWidget *event_box; GtkSizeGroup *encryption_size_group; GtkTooltips *tooltips; @@ -172,11 +182,13 @@ typedef struct GladeXML *xml; } DriverNotifyCBData; -NetworkDevice *nmwa_get_device_for_nm_device (GSList *dev_list, const char *nm_dev); -WirelessNetwork *nmwa_get_net_for_nm_net (NetworkDevice *dev, const char *net_path); -WirelessNetwork *nmwa_get_net_by_essid (NetworkDevice *dev, const char *essid); -NMWirelessApplet *nmwa_new (void); -void show_warning_dialog (gboolean error, gchar *mesg, ...); -gboolean nmwa_driver_notify (gpointer user_data); +NetworkDevice * nmwa_get_device_for_nm_device (GSList *dev_list, const char *nm_dev); +WirelessNetwork * nmwa_get_net_for_nm_net (NetworkDevice *dev, const char *net_path); +WirelessNetwork * nmwa_get_net_by_essid (NetworkDevice *dev, const char *essid); +NMWirelessApplet * nmwa_new (void); +void show_warning_dialog (gboolean error, gchar *mesg, ...); +gboolean nmwa_driver_notify (gpointer user_data); +void nmwa_schedule_vpn_login_failure_dialog (NMWirelessApplet *applet, const char *vpn_name, const char *error_msg); +void nmwa_schedule_vpn_login_banner_dialog (NMWirelessApplet *applet, const char *vpn_name, const char *banner); #endif diff --git a/panel-applet/NMWirelessAppletDbus.c b/panel-applet/NMWirelessAppletDbus.c index cfd7e9aa9..cb2ee75b1 100644 --- a/panel-applet/NMWirelessAppletDbus.c +++ b/panel-applet/NMWirelessAppletDbus.c @@ -29,6 +29,7 @@ #include #include "NMWirelessAppletDbus.h" #include "NMWirelessApplet.h" +#include "nmwa-vpn-connection.h" #include "nm-utils.h" @@ -118,6 +119,10 @@ static int nmwa_dbus_call_nm_method (DBusConnection *con, const char *path, cons ret = RETURN_SUCCESS; else if (!strcmp (error.name, NM_DBUS_NO_NETWORKS_ERROR)) ret = RETURN_SUCCESS; + else if (!strcmp (error.name, NM_DBUS_NO_ACTIVE_VPN_CONNECTION)) + ret = RETURN_SUCCESS; + else if (!strcmp (error.name, NM_DBUS_NO_VPN_CONNECTIONS)) + ret = RETURN_SUCCESS; if ((ret != RETURN_SUCCESS) && (ret != RETURN_NO_NM)) fprintf (stderr, "nmwa_dbus_call_nm_method(): %s raised on method '%s':\n %s\n\n", error.name, method, error.message); @@ -258,6 +263,30 @@ static char * nmwa_dbus_get_active_network (NMWirelessApplet *applet, char *dev_ } +/* + * nmwa_dbus_get_active_vpn_connection + * + * Return the name of the currently active VPN connection. + * + */ +static char * nmwa_dbus_get_active_vpn_connection (NMWirelessApplet *applet) +{ + char *name = NULL; + + switch (nmwa_dbus_call_nm_method (applet->connection, NM_DBUS_PATH_VPN, "getActiveVPNConnection", DBUS_TYPE_STRING, (void **)(&name), NULL)) + { + case (RETURN_NO_NM): + applet->applet_state = APPLET_STATE_NO_NM; + break; + + default: + break; + } + + return (name); +} + + /* * nmwa_dbus_get_device_type * @@ -580,6 +609,35 @@ static char **nmwa_dbus_get_device_networks (NMWirelessApplet *applet, char *pat } +/* + * nmwa_dbus_get_vpn_connections + * + * Returns an array of wireless networks that the specified device knows about. + * + */ +static char **nmwa_dbus_get_vpn_connections (NMWirelessApplet *applet, int *num_items) +{ + char **array = NULL; + int items; + + switch (nmwa_dbus_call_nm_method (applet->connection, NM_DBUS_PATH_VPN, "getVPNConnections", NM_DBUS_TYPE_STRING_ARRAY, (void **)(&array), &items)) + { + case (RETURN_NO_NM): + applet->applet_state = APPLET_STATE_NO_NM; + break; + + case (RETURN_SUCCESS): + *num_items = items; + break; + + default: + break; + } + + return (array); +} + + /* * nmwa_dbus_get_hal_device_string_property * @@ -704,6 +762,54 @@ void nmwa_dbus_set_device (DBusConnection *connection, const NetworkDevice *dev, } +/* + * nmwa_dbus_vpn_activate_connection + * + * Tell NetworkManager to activate a particular VPN connection. + * + */ +void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, const char *password) +{ + DBusMessage *message; + + g_return_if_fail (connection != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (password != NULL); + + if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "activateVPNConnection"))) + { + fprintf (stderr, "Activating VPN connection '%s'.\n", name); + + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &password, DBUS_TYPE_INVALID); + dbus_connection_send (connection, message, NULL); + } + else + fprintf (stderr, "nmwa_dbus_activate_vpn_connection(): Couldn't allocate the dbus message\n"); +} + + +/* + * nmwa_dbus_deactivate_vpn_connection + * + * Tell NetworkManager to deactivate the currently active VPN connection. + * + */ +void nmwa_dbus_vpn_deactivate_connection (DBusConnection *connection) +{ + DBusMessage *message; + + g_return_if_fail (connection != NULL); + + if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "deactivateVPNConnection"))) + { + fprintf (stderr, "Deactivating the current VPN connection.\n"); + dbus_connection_send (connection, message, NULL); + } + else + fprintf (stderr, "nmwa_dbus_activate_vpn_connection(): Couldn't allocate the dbus message\n"); +} + + /* * nmwa_dbus_create_network * @@ -1149,6 +1255,17 @@ void nmwa_free_gui_data_model (NMWirelessApplet *applet) g_free (applet->gui_nm_status); applet->gui_nm_status = NULL; } + + if (applet->gui_active_vpn) + nmwa_vpn_connection_unref (applet->gui_active_vpn, __FUNCTION__); + applet->gui_active_vpn = NULL; + + if (applet->gui_vpn_connections) + { + g_slist_foreach (applet->gui_vpn_connections, (GFunc) nmwa_vpn_connection_unref, (gpointer)__FUNCTION__); + g_slist_free (applet->gui_vpn_connections); + applet->gui_vpn_connections = NULL; + } } @@ -1172,6 +1289,17 @@ void nmwa_free_dbus_data_model (NMWirelessApplet *applet) g_free (applet->dbus_nm_status); applet->dbus_nm_status = NULL; } + + if (applet->dbus_active_vpn) + nmwa_vpn_connection_unref (applet->dbus_active_vpn, __FUNCTION__); + applet->dbus_active_vpn = NULL; + + if (applet->dbus_vpn_connections) + { + g_slist_foreach (applet->dbus_vpn_connections, (GFunc) nmwa_vpn_connection_unref, (gpointer)__FUNCTION__); + g_slist_free (applet->dbus_vpn_connections); + applet->dbus_vpn_connections = NULL; + } } @@ -1214,6 +1342,23 @@ void nmwa_copy_data_model (NMWirelessApplet *applet) /* active_device is just a pointer into the device list, no need to deep-copy it */ applet->gui_active_device = act_dev; applet->gui_nm_status = g_strdup (applet->dbus_nm_status); + + /* Deep-copy VPN connections to GUI data model */ + for (elt = applet->dbus_vpn_connections; elt; elt = g_slist_next (elt)) + { + VPNConnection *src_vpn = elt->data; + VPNConnection *new_vpn = nmwa_vpn_connection_copy (src_vpn, __FUNCTION__); + + if (new_vpn) + { + applet->gui_vpn_connections = g_slist_append (applet->gui_vpn_connections, new_vpn); + if (applet->dbus_active_vpn == src_vpn) + { + nmwa_vpn_connection_ref (new_vpn, __FUNCTION__); + applet->gui_active_vpn = new_vpn; + } + } + } } @@ -1470,6 +1615,17 @@ sort_devices_function (gconstpointer a, gconstpointer b) } +static void nmwa_dbus_lock_and_copy_data_model (NMWirelessApplet *applet) +{ + g_return_if_fail (applet != NULL); + + /* Now copy the data over to the GUI side */ + g_mutex_lock (applet->data_mutex); + nmwa_copy_data_model (applet); + g_mutex_unlock (applet->data_mutex); +} + + /* * nmwa_dbus_update_devices * @@ -1484,6 +1640,8 @@ static void nmwa_dbus_update_devices (NMWirelessApplet *applet) gboolean adhoc = FALSE; char *nm_act_dev; char *nm_status; + gboolean scanning_enabled; + gboolean wireless_enabled; g_return_if_fail (applet->data_mutex != NULL); @@ -1560,15 +1718,124 @@ static void nmwa_dbus_update_devices (NMWirelessApplet *applet) /* Notify user of issues with certain cards/drivers */ nmwa_dbus_check_drivers (applet); - /* Now copy the data over to the GUI side */ - g_mutex_lock (applet->data_mutex); - - nmwa_copy_data_model (applet); applet->is_adhoc = adhoc; applet->scanning_enabled = nmwa_dbus_get_scanning_enabled (applet); applet->wireless_enabled = nmwa_dbus_get_wireless_enabled (applet); +} - g_mutex_unlock (applet->data_mutex); + +/* + * nmwa_dbus_update_one_vpn_connection + * + * Grab properties of one VPN connection from NetworkManager. + * + */ +void nmwa_dbus_update_one_vpn_connection (DBusConnection *connection, const char *name, NMWirelessApplet *applet, gboolean is_active) +{ + DBusMessage *message; + DBusError error; + DBusMessage *reply; + const char *user_name = NULL; + DBusMessageIter iter; + + g_return_if_fail (connection != NULL); + g_return_if_fail (applet != NULL); + g_return_if_fail (name != NULL); + + if (!(message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "getVPNConnectionProperties"))) + { + nm_warning ("Couldn't allocate the dbus message"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + + /* Send message and get properties back from NetworkManager */ + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + { + nm_warning ("nmwa_dbus_update_one_vpn_connection(): %s raised %s", error.name, error.message); + goto out; + } + else if (!reply) + goto out; + else + { + VPNConnection *vpn; + + dbus_message_iter_init (reply, &iter); + + /* Skip name, we already know it */ + dbus_message_iter_next (&iter); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + { + nm_warning ("Reply had wrong arguments: " + "(expected %u, got %u)\n", DBUS_TYPE_STRING, + dbus_message_iter_get_arg_type (&iter)); + goto out; + } + dbus_message_iter_get_basic (&iter, &user_name); + + if (!(vpn = nmwa_vpn_connection_find_by_name (applet->dbus_vpn_connections, name))) + { + vpn = nmwa_vpn_connection_new (name, __FUNCTION__); + nmwa_vpn_connection_set_user_name (vpn, user_name); + applet->dbus_vpn_connections = g_slist_append (applet->dbus_vpn_connections, vpn); + } + else + nmwa_vpn_connection_set_user_name (vpn, user_name); + + if (is_active) + { + nmwa_vpn_connection_ref (vpn, __FUNCTION__); + applet->dbus_active_vpn = vpn; + } + } + +out: + if (reply) + dbus_message_unref (reply); +} + + +/* + * nmwa_dbus_update_vpn_connections + * + * Grab a list of all VPN connections from NetworkManager. + * + */ +static void nmwa_dbus_update_vpn_connections (NMWirelessApplet *applet) +{ + char **names; + int num_items = 0; + char *active; + + g_return_if_fail (applet != NULL); + + g_slist_foreach (applet->dbus_vpn_connections, (GFunc) nmwa_vpn_connection_unref, (gpointer)__FUNCTION__); + g_slist_free (applet->dbus_vpn_connections); + applet->dbus_vpn_connections = NULL; + + if (applet->dbus_active_vpn) + nmwa_vpn_connection_unref (applet->dbus_active_vpn, __FUNCTION__); + applet->dbus_active_vpn = NULL; + + active = nmwa_dbus_get_active_vpn_connection (applet); + if ((names = nmwa_dbus_get_vpn_connections (applet, &num_items))) + { + int i; + + for (i = 0; i < num_items; i++) + { + gboolean is_active = active ? (strcmp (active, names[i]) == 0) : FALSE; + nmwa_dbus_update_one_vpn_connection (applet->connection, names[i], applet, is_active); + } + g_strfreev (names); + } + g_free (active); } @@ -1594,11 +1861,11 @@ static DBusHandlerResult nmwa_dbus_filter (DBusConnection *connection, DBusMessa char *old_owner; char *new_owner; - if ( dbus_message_get_args (message, &error, - DBUS_TYPE_STRING, &service, - DBUS_TYPE_STRING, &old_owner, - DBUS_TYPE_STRING, &new_owner, - DBUS_TYPE_INVALID)) + if (dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { gboolean old_owner_good = (old_owner && (strlen (old_owner) > 0)); gboolean new_owner_good = (new_owner && (strlen (new_owner) > 0)); @@ -1621,6 +1888,16 @@ static DBusHandlerResult nmwa_dbus_filter (DBusConnection *connection, DBusMessa } else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "WirelessNetworkUpdate")) nmwa_dbus_device_update_one_network (applet, message); + else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionUpdate")) + { + char *name; + + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + { + nmwa_dbus_update_one_vpn_connection (applet->connection, name, applet, FALSE); + nmwa_dbus_lock_and_copy_data_model (applet); + } + } else if ( dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNowActive") || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNoLongerActive") || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceActivating") @@ -1628,6 +1905,29 @@ static DBusHandlerResult nmwa_dbus_filter (DBusConnection *connection, DBusMessa || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DevicesChanged")) { nmwa_dbus_update_devices (applet); + nmwa_dbus_update_vpn_connections (applet); + nmwa_dbus_lock_and_copy_data_model (applet); + } + else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionChange")) + { + nmwa_dbus_update_vpn_connections (applet); + nmwa_dbus_lock_and_copy_data_model (applet); + } + else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNLoginFailed")) + { + char *vpn_name; + char *error_msg; + + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) + nmwa_schedule_vpn_login_failure_dialog (applet, vpn_name, error_msg); + } + else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNLoginBanner")) + { + char *vpn_name; + char *banner; + + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) + nmwa_schedule_vpn_login_banner_dialog (applet, vpn_name, banner); } else handled = FALSE; @@ -1706,6 +2006,15 @@ static DBusConnection * nmwa_dbus_init (NMWirelessApplet *applet, GMainContext * if (dbus_error_is_set (&error)) dbus_error_free (&error); + dbus_bus_add_match(connection, + "type='signal'," + "interface='" NM_DBUS_INTERFACE_VPN "'," + "path='" NM_DBUS_PATH_VPN "'," + "sender='" NM_DBUS_SERVICE "'", + &error); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + return (connection); } @@ -1731,6 +2040,8 @@ static gboolean nmwa_dbus_timeout_worker (gpointer user_data) { applet->applet_state = APPLET_STATE_NO_CONNECTION; nmwa_dbus_update_devices (applet); + nmwa_dbus_update_vpn_connections (applet); + nmwa_dbus_lock_and_copy_data_model (applet); } } @@ -1776,6 +2087,8 @@ gpointer nmwa_dbus_worker (gpointer user_data) { applet->applet_state = APPLET_STATE_NO_CONNECTION; nmwa_dbus_update_devices (applet); + nmwa_dbus_update_vpn_connections (applet); + nmwa_dbus_lock_and_copy_data_model (applet); } else applet->applet_state = APPLET_STATE_NO_NM; diff --git a/panel-applet/NMWirelessAppletDbus.h b/panel-applet/NMWirelessAppletDbus.h index 14a90386c..445f342d5 100644 --- a/panel-applet/NMWirelessAppletDbus.h +++ b/panel-applet/NMWirelessAppletDbus.h @@ -59,5 +59,7 @@ void network_device_unref (NetworkDevice *dev); void nmwa_free_gui_data_model (NMWirelessApplet *applet); void nmwa_free_dbus_data_model (NMWirelessApplet *applet); +void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, const char *password); +void nmwa_dbus_vpn_deactivate_connection(DBusConnection *connection); #endif diff --git a/panel-applet/icons/Makefile.am b/panel-applet/icons/Makefile.am index 5fddd90db..2b09951f2 100644 --- a/panel-applet/icons/Makefile.am +++ b/panel-applet/icons/Makefile.am @@ -42,6 +42,7 @@ smallicon_DATA= \ nm-signal-50.png \ nm-signal-75.png \ nm-signal-100.png \ + nm-vpn-lock.png \ $(NULL) EXTRA_DIST=\ diff --git a/panel-applet/icons/nm-vpn-lock.png b/panel-applet/icons/nm-vpn-lock.png new file mode 100644 index 000000000..73d1a4131 Binary files /dev/null and b/panel-applet/icons/nm-vpn-lock.png differ diff --git a/panel-applet/nmwa-vpn-connection.c b/panel-applet/nmwa-vpn-connection.c new file mode 100644 index 000000000..02563b712 --- /dev/null +++ b/panel-applet/nmwa-vpn-connection.c @@ -0,0 +1,138 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#include +#include "nmwa-vpn-connection.h" + + +struct VPNConnection +{ + int refcount; + char *name; + char *user_name; +}; + + +VPNConnection *nmwa_vpn_connection_new (const char *name, const char *func) +{ + VPNConnection *vpn; + + g_return_val_if_fail (name != NULL, NULL); + + vpn = g_malloc0 (sizeof (VPNConnection)); + vpn->refcount = 1; + vpn->name = g_strdup (name); + + return vpn; +} + + +VPNConnection *nmwa_vpn_connection_copy (VPNConnection *src_vpn, const char *func) +{ + VPNConnection *dst_vpn; + + g_return_val_if_fail (src_vpn != NULL, NULL); + + dst_vpn = g_malloc0 (sizeof (VPNConnection)); + dst_vpn->refcount = 1; + dst_vpn->name = g_strdup (src_vpn->name); + dst_vpn->user_name = src_vpn->user_name ? g_strdup (src_vpn->user_name) : NULL; + + return dst_vpn; +} + + +void nmwa_vpn_connection_ref (VPNConnection *vpn, const char *func) +{ + g_return_if_fail (vpn != NULL); + + vpn->refcount++; +} + + +void nmwa_vpn_connection_unref (VPNConnection *vpn, const char *func) +{ + g_return_if_fail (vpn != NULL); + + vpn->refcount--; + if (vpn->refcount <= 0) + { + g_free (vpn->name); + g_free (vpn->user_name); + memset (vpn, 0, sizeof (VPNConnection)); + g_free (vpn); + } +} + + +const char *nmwa_vpn_connection_get_name (VPNConnection *vpn) +{ + g_return_val_if_fail (vpn != NULL, NULL); + + return vpn->name; +} + + +const char *nmwa_vpn_connection_get_user_name (VPNConnection *vpn) +{ + g_return_val_if_fail (vpn != NULL, NULL); + + return vpn->user_name; +} + + +void nmwa_vpn_connection_set_user_name (VPNConnection *vpn, const char *user_name) +{ + g_return_if_fail (vpn != NULL); + g_return_if_fail (user_name != NULL); + + g_free (vpn->user_name); + vpn->user_name = g_strdup (user_name); +} + + + +static int is_same_name (VPNConnection *vpn, const char *name) +{ + if (!vpn || !name || !nmwa_vpn_connection_get_name (vpn)) + return -1; + + return strcmp (nmwa_vpn_connection_get_name (vpn), name); +} + + +VPNConnection *nmwa_vpn_connection_find_by_name (GSList *list, const char *name) +{ + GSList *elt; + VPNConnection *vpn = NULL; + + g_return_val_if_fail (name != NULL, NULL); + + if (!list) + return NULL; + + if ((elt = g_slist_find_custom (list, name, (GCompareFunc) is_same_name))) + vpn = elt->data; + + return vpn; +} + + diff --git a/panel-applet/nmwa-vpn-connection.h b/panel-applet/nmwa-vpn-connection.h new file mode 100644 index 000000000..88fe2def3 --- /dev/null +++ b/panel-applet/nmwa-vpn-connection.h @@ -0,0 +1,39 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#ifndef NMWA_VPN_CONNECTION_H +#define NMWA_VPN_CONNECTION_H + +#include "NMWirelessApplet.h" + +VPNConnection * nmwa_vpn_connection_new (const char *name, const char *func); +VPNConnection * nmwa_vpn_connection_copy (VPNConnection *vpn, const char *func); +void nmwa_vpn_connection_ref (VPNConnection *vpn, const char *func); +void nmwa_vpn_connection_unref (VPNConnection *vpn, const char *func); + +const char * nmwa_vpn_connection_get_name (VPNConnection *vpn); + +const char * nmwa_vpn_connection_get_user_name (VPNConnection *vpn); +void nmwa_vpn_connection_set_user_name (VPNConnection *vpn, const char *user_name); + +VPNConnection * nmwa_vpn_connection_find_by_name (GSList *list, const char *name); + +#endif diff --git a/panel-applet/nmwa-vpn-password-dialog.c b/panel-applet/nmwa-vpn-password-dialog.c new file mode 100644 index 000000000..dcb09b28b --- /dev/null +++ b/panel-applet/nmwa-vpn-password-dialog.c @@ -0,0 +1,134 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _ +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x +#endif + +#include "NMWirelessApplet.h" +#include "nmwa-vpn-password-dialog.h" +#include "nm-utils.h" + +static gboolean lookup_pass (const char *vpn, const char *username, char **password) +{ + GList *result; + + if (gnome_keyring_find_network_password_sync (username, + NULL, + vpn, + NULL, + "vpn", + NULL, + 0, + &result) != GNOME_KEYRING_RESULT_OK) + return FALSE; + + if (result) + { + GnomeKeyringNetworkPasswordData *data = result->data; + *password = g_strdup (data->password); + gnome_keyring_network_password_list_free (result); + return TRUE; + } + return FALSE; +} + +static void save_vpn_password (const char *vpn, const char *keyring, const char *username, const char *password) +{ + guint32 item_id; + GnomeKeyringResult keyring_result; + + keyring_result = gnome_keyring_set_network_password_sync (NULL, + username, + NULL, + vpn, + NULL, + "vpn", + NULL, + 0, + password, + &item_id); + + if (keyring_result != GNOME_KEYRING_RESULT_OK) + { + nm_warning ("Couldn't store password in keyring, code %d", + (int) keyring_result); + } +} + +char *nmwa_vpn_request_password (NMWirelessApplet *applet, const char *vpn, const char *username, gboolean retry) +{ + GtkWidget *dialog; + char *prompt; + char *password = NULL; + + g_return_val_if_fail (applet != NULL, NULL); + g_return_val_if_fail (vpn != NULL, NULL); + g_return_val_if_fail (username != NULL, NULL); + + /* Use the system user name, since the VPN might have a different user name */ + if (!retry && lookup_pass (vpn, g_get_user_name (), &password)) + return password; + + prompt = g_strdup_printf (_("You must log in to access the Virtual Private Network '%s'."), vpn); + dialog = gnome_password_dialog_new ("", prompt, username, NULL, FALSE); + g_free (prompt); + + gnome_password_dialog_set_show_username (GNOME_PASSWORD_DIALOG (dialog), TRUE); + gnome_password_dialog_set_readonly_username (GNOME_PASSWORD_DIALOG (dialog), TRUE); + gnome_password_dialog_set_show_userpass_buttons (GNOME_PASSWORD_DIALOG (dialog), FALSE); + gnome_password_dialog_set_show_domain (GNOME_PASSWORD_DIALOG (dialog), FALSE); + gnome_password_dialog_set_show_remember (GNOME_PASSWORD_DIALOG (dialog), TRUE); + gtk_widget_show (dialog); + + if (gnome_password_dialog_run_and_block (GNOME_PASSWORD_DIALOG (dialog))) + { + password = gnome_password_dialog_get_password (GNOME_PASSWORD_DIALOG (dialog)); + switch (gnome_password_dialog_get_remember (GNOME_PASSWORD_DIALOG (dialog))) + { + case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION: + save_vpn_password (vpn, "session", username, password); + break; + case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER: + save_vpn_password (vpn, NULL, username, password); + break; + default: + break; + } + } + + gtk_widget_destroy (dialog); + return password; +} diff --git a/panel-applet/nmwa-vpn-password-dialog.h b/panel-applet/nmwa-vpn-password-dialog.h new file mode 100644 index 000000000..5ded52aef --- /dev/null +++ b/panel-applet/nmwa-vpn-password-dialog.h @@ -0,0 +1,29 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#ifndef NMWA_VPN_PASSWORD_DIALOG_H +#define NMWA_VPN_PASSWORD_DIALOG_H + +#include "NMWirelessApplet.h" + +char *nmwa_vpn_request_password (NMWirelessApplet *applet, const char *vpn, const char *username, gboolean retry); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 5a3b5cc45..880e6e0c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,9 @@ -INCLUDES = -I${top_srcdir} -I${top_srcdir}/named -I${top_srcdir}/utils +SUBDIRS=named-manager vpn-manager backends + +INCLUDES = -I${top_srcdir} -I./named-manager -I./vpn-manager -I${top_srcdir}/utils bin_PROGRAMS = NetworkManager -noinst_LTLIBRARIES = libnmbackend.la - NetworkManager_SOURCES = \ NetworkManagerAP.c \ NetworkManagerAP.h \ @@ -28,6 +28,8 @@ NetworkManager_SOURCES = \ NetworkManagerDevice.c \ NetworkManagerDevice.h \ NetworkManagerDevicePrivate.h \ + nm-ip4-config.c \ + nm-ip4-config.h \ NetworkManager.c \ NetworkManagerMain.h \ NetworkManagerPolicy.c \ @@ -53,6 +55,7 @@ NetworkManager_CPPFLAGS = \ -DG_DISABLE_DEPRECATED \ -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ -DARP_DEBUG if WITH_GCRYPT NetworkManager_CPPFLAGS += $(LIBGCRYPT_CFLAGS) @@ -63,41 +66,21 @@ if !WITH_GCRYPT NetworkManager_SOURCES += gnome-keyring-md5.c gnome-keyring-md5.h endif -NetworkManager_LDADD = \ - $(DBUS_LIBS) \ - $(GTHREAD_LIBS) \ - $(HAL_LIBS) \ - $(IWLIB) \ - libnmbackend.la \ +NetworkManager_LDADD = \ + $(DBUS_LIBS) \ + $(GTHREAD_LIBS) \ + $(HAL_LIBS) \ + $(IWLIB) \ $(top_builddir)/utils/libnmutils.la \ - ../dhcpcd/libdhcpc.a \ - ../named/libnamed.la + ../dhcpcd/libdhcpc.a \ + ./named-manager/libnamed-manager.la \ + ./vpn-manager/libvpn-manager.la \ + ./backends/libnmbackend.la + if WITH_GCRYPT NetworkManager_LDADD += $(LIBGCRYPT_LIBS) endif -libnmbackend_la_SOURCES = - -if TARGET_REDHAT -libnmbackend_la_SOURCES += backends/NetworkManagerRedHat.c \ - backends/shvar.c \ - backends/shvar.h -endif -if TARGET_GENTOO -libnmbackend_la_SOURCES += backends/NetworkManagerGentoo.c -endif -if TARGET_DEBIAN -libnmbackend_la_SOURCES += backends/NetworkManagerDebian.c \ - backends/interface_parser.c \ - backends/interface_parser.h -endif -if TARGET_SLACKWARE -libnmbackend_la_SOURCES += backends/NetworkManagerSlackware.c -endif - -libnmbackend_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) -libnmbackend_la_CFLAGS = $(NetworkManager_CPPFLAGS) - dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = NetworkManager.conf diff --git a/src/NetworkManager.c b/src/NetworkManager.c index d8c776e0a..de3c71907 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -44,6 +44,7 @@ #include "NetworkManagerAPList.h" #include "NetworkManagerSystem.h" #include "nm-named-manager.h" +#include "nm-dbus-vpn.h" #include "nm-netlink-monitor.h" #define NM_WIRELESS_LINK_STATE_POLL_INTERVAL (5 * 1000) @@ -512,7 +513,9 @@ static void nm_data_free (NMData *data) { g_return_if_fail (data != NULL); + nm_vpn_manager_dispose (data->vpn_manager); g_object_unref (data->named); + nm_device_unref (data->active_device); g_slist_foreach (data->dev_list, (GFunc) nm_device_unref, NULL); @@ -844,10 +847,14 @@ int main( int argc, char *argv[] ) exit (EXIT_FAILURE); } - /* If NMI is running, grab allowed wireless network lists from it ASAP - */ + nm_data->vpn_manager = nm_vpn_manager_new (nm_data); + + /* If NMI is running, grab allowed wireless network lists from it ASAP */ if (nm_dbus_is_info_daemon_running (nm_data->dbus_connection)) + { nm_policy_schedule_allowed_ap_list_update (nm_data); + nm_dbus_vpn_schedule_vpn_connections_update (nm_data); + } /* Right before we init hal, we have to make sure our mainloop * integration function knows about our GMainContext. HAL doesn't give @@ -865,7 +872,7 @@ int main( int argc, char *argv[] ) nm_hal_mainloop_integration (ctx, nm_data->dbus_connection); - libhal_ctx_set_dbus_connection (ctx, nm_data->dbus_connection); + libhal_ctx_set_dbus_connection (ctx, nm_data->dbus_connection); dbus_error_init (&dbus_error); if(!libhal_ctx_init (ctx, &dbus_error)) { @@ -929,7 +936,6 @@ int main( int argc, char *argv[] ) /* Cleanup */ libhal_ctx_shutdown (nm_data->hal_ctx, &dbus_error); - if (dbus_error_is_set (&dbus_error)) { nm_warning ("libhal shutdown failed - %s", dbus_error.message); diff --git a/src/NetworkManagerDHCP.c b/src/NetworkManagerDHCP.c index 895c18a17..e7f069b48 100644 --- a/src/NetworkManagerDHCP.c +++ b/src/NetworkManagerDHCP.c @@ -37,169 +37,33 @@ extern gboolean get_autoip (NMDevice *dev, struct in_addr *out_ip); -static void set_nameservers (NMDevice *dev, void *data, int len) -{ - int i; - GList *elt; - GError *error = NULL; - - /* Reset our nameserver list */ - for (elt = dev->app_data->nameserver_ids; elt; elt = elt->next) - { - if (!nm_named_manager_remove_nameserver_ipv4 (dev->app_data->named, - GPOINTER_TO_UINT (elt->data), - &error)) - { - nm_warning ("Couldn't remove nameserver: %s", error->message); - g_clear_error (&error); - } - } - g_list_free (dev->app_data->nameserver_ids); - dev->app_data->nameserver_ids = NULL; - - for (i = 0; data && (i < len-3); i += 4) - { - char *nameserver; - guint id; - nameserver = g_strdup_printf ("%u.%u.%u.%u", - ((unsigned char *)data)[i], - ((unsigned char *)data)[i+1], - ((unsigned char *)data)[i+2], - ((unsigned char *)data)[i+3]); - nm_info ("Adding nameserver: %s", nameserver); - - if ((id = nm_named_manager_add_nameserver_ipv4 (dev->app_data->named, - nameserver, - &error))) - dev->app_data->nameserver_ids = g_list_prepend (dev->app_data->nameserver_ids, - GUINT_TO_POINTER (id)); - else - { - nm_warning ("Couldn't add nameserver: %s\n", error->message); - g_clear_error (&error); - } - g_free (nameserver); - } -} - -static void set_domain_searches (NMDevice *dev, const char *searches_str) -{ - GError *error = NULL; - GList *elt; - char **searches, **s; - - /* Reset our domain search list */ - for (elt = dev->app_data->domain_search_ids; elt; elt = elt->next) - { - if (!nm_named_manager_remove_domain_search (dev->app_data->named, - GPOINTER_TO_UINT (elt->data), - &error)) - { - nm_warning ("Couldn't remove domain search: %s\n", error->message); - g_clear_error (&error); - } - } - g_list_free (dev->app_data->domain_search_ids); - dev->app_data->domain_search_ids = NULL; - - searches = g_strsplit (searches_str, " ", 0); - - for (s = searches; *s; s++) - { - const char *search_elt = *s; - guint id; - - nm_warning ("Adding domain search: %s\n", search_elt); - if ((id = nm_named_manager_add_domain_search (dev->app_data->named, - search_elt, - &error))) - dev->app_data->domain_search_ids = g_list_append (dev->app_data->domain_search_ids, GUINT_TO_POINTER (id)); - else - { - nm_warning ("Couldn't add domain search: %s\n", error->message); - g_clear_error (&error); - } - } - g_strfreev (searches); -} - /* - * nm_device_dhcp_configure + * nm_device_new_ip4_autoip_config * - * Using the results of a DHCP request, configure the device. + * Build up an IP config with a Link Local address * */ -static void nm_device_dhcp_configure (NMDevice *dev) -{ - int temp; - - g_return_if_fail (dev != NULL); - g_return_if_fail (dev->dhcp_iface != NULL); - - /* DHCP sets up a default route for the device, we need to remove that. */ - nm_system_device_flush_routes (dev); - - /* Replace basic info */ - nm_system_device_set_ip4_address (dev, dev->dhcp_iface->ciaddr); - - if (dhcp_interface_option_present (dev->dhcp_iface, subnetMask)) - { - memcpy (&temp, dhcp_interface_option_payload (dev->dhcp_iface, subnetMask), dhcp_option_element_len (subnetMask)); - nm_system_device_set_ip4_netmask (dev, temp); - } - - if (dhcp_interface_option_present (dev->dhcp_iface, broadcastAddr)) - { - memcpy (&temp, dhcp_interface_option_payload (dev->dhcp_iface, broadcastAddr), dhcp_option_element_len (broadcastAddr)); - nm_system_device_set_ip4_broadcast (dev, temp); - } - - /* Default route */ - if (dhcp_interface_option_present (dev->dhcp_iface, routersOnSubnet)) - { - memcpy (&temp, dhcp_interface_option_payload (dev->dhcp_iface, routersOnSubnet), dhcp_option_element_len (routersOnSubnet)); - nm_system_device_set_ip4_default_route (dev, temp); - } - - /* Update /etc/resolv.conf */ - if (dhcp_interface_option_present (dev->dhcp_iface, dns)) - set_nameservers (dev, dhcp_interface_option_payload (dev->dhcp_iface, dns), dhcp_interface_option_len (dev->dhcp_iface, dns)); - - if (dhcp_interface_option_present (dev->dhcp_iface, domainName)) - set_domain_searches (dev, dhcp_interface_option_payload (dev->dhcp_iface, domainName)); -} - - -/* - * nm_device_do_autoip - * - * Get and assign a Link Local Address. - * - */ -gboolean nm_device_do_autoip (NMDevice *dev) +NMIP4Config *nm_device_new_ip4_autoip_config (NMDevice *dev) { struct in_addr ip; - gboolean success = FALSE; + NMIP4Config * config = NULL; - g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev != NULL, NULL); - if ((success = get_autoip (dev, &ip))) + if (get_autoip (dev, &ip)) { #define LINKLOCAL_BCAST 0xa9feffff int temp = ip.s_addr; - nm_system_device_set_ip4_address (dev, temp); - temp = ntohl (0xFFFF0000); - nm_system_device_set_ip4_netmask (dev, temp); - temp = ntohl (LINKLOCAL_BCAST); - nm_system_device_set_ip4_broadcast (dev, temp); + config = nm_ip4_config_new (); - /* Set all traffic to go through the device */ - nm_system_flush_loopback_routes (); - nm_system_device_add_default_route_via_device (dev); + nm_ip4_config_set_address (config, (guint32)(ip.s_addr)); + nm_ip4_config_set_netmask (config, (guint32)(ntohl (0xFFFF0000))); + nm_ip4_config_set_broadcast (config, (guint32)(ntohl (LINKLOCAL_BCAST))); + nm_ip4_config_set_gateway (config, 0); } - return (success); + return config; } @@ -209,7 +73,7 @@ gboolean nm_device_do_autoip (NMDevice *dev) * Start a DHCP transaction on particular device. * */ -int nm_device_dhcp_request (NMDevice *dev) +static int nm_device_dhcp_request (NMDevice *dev) { dhcp_client_options opts; int err; @@ -232,18 +96,84 @@ int nm_device_dhcp_request (NMDevice *dev) * and settings. */ if ((err = dhcp_init (dev->dhcp_iface)) == RET_DHCP_BOUND) - { - nm_device_dhcp_configure (dev); - nm_device_update_ip4_address (dev); nm_device_dhcp_setup_timeouts (dev); - } else { dhcp_interface_free (dev->dhcp_iface); dev->dhcp_iface = NULL; } - return (err); + return err; +} + + +/* + * nm_device_new_ip4_dhcp_config + * + * Get IPv4 configuration info via DHCP, running the DHCP + * transaction if necessary. + * + */ +NMIP4Config *nm_device_new_ip4_dhcp_config (NMDevice *dev) +{ + NMIP4Config * config = NULL; + int err; + dhcp_interface *dhcp_info = NULL; + + g_return_val_if_fail (dev != NULL, NULL); + + err = nm_device_dhcp_request (dev); + dhcp_info = dev->dhcp_iface; + if ((err == RET_DHCP_BOUND) && dev->dhcp_iface) + { + guint32 temp; + + config = nm_ip4_config_new (); + + nm_ip4_config_set_address (config, dhcp_info->ciaddr); + + if (dhcp_interface_option_present (dhcp_info, subnetMask)) + { + memcpy (&temp, dhcp_interface_option_payload (dhcp_info, subnetMask), dhcp_option_element_len (subnetMask)); + nm_ip4_config_set_netmask (config, temp); + } + + if (dhcp_interface_option_present (dhcp_info, broadcastAddr)) + { + memcpy (&temp, dhcp_interface_option_payload (dhcp_info, broadcastAddr), dhcp_option_element_len (broadcastAddr)); + nm_ip4_config_set_broadcast (config, temp); + } + + /* Default route */ + if (dhcp_interface_option_present (dhcp_info, routersOnSubnet)) + { + memcpy (&temp, dhcp_interface_option_payload (dhcp_info, routersOnSubnet), dhcp_option_element_len (routersOnSubnet)); + nm_ip4_config_set_gateway (config, temp); + } + + /* Update /etc/resolv.conf */ + if (dhcp_interface_option_present (dhcp_info, dns)) + { + guint32 *data = dhcp_interface_option_payload (dhcp_info, dns); + int len = dhcp_interface_option_len (dhcp_info, dns) / sizeof (guint32); + + for (temp = 0; temp < len; temp++) + nm_ip4_config_add_nameserver (config, data[temp]); + } + + if (dhcp_interface_option_present (dhcp_info, domainName)) + { + char **searches = g_strsplit (dhcp_interface_option_payload (dev->dhcp_iface, domainName), " ", 0); + char **s; + + for (s = searches; *s; s++) + nm_ip4_config_add_domain (config, *s); + + g_strfreev (searches); + } + } + + return config; } @@ -348,7 +278,7 @@ gboolean nm_device_dhcp_renew (gpointer user_data) /* If the T1 renewal fails, then we wait around until T2 * for rebind. */ - return (FALSE); + return FALSE; } else { @@ -359,7 +289,7 @@ gboolean nm_device_dhcp_renew (gpointer user_data) /* Always return false to remove ourselves, since we just * set up another timeout above. */ - return (FALSE); + return FALSE; } @@ -392,7 +322,7 @@ gboolean nm_device_dhcp_rebind (gpointer user_data) dhcp_interface_free (dev->dhcp_iface); dev->dhcp_iface = NULL; - return (FALSE); + return FALSE; } else { @@ -403,6 +333,6 @@ gboolean nm_device_dhcp_rebind (gpointer user_data) /* Always return false to remove ourselves, since we just * set up another timeout above. */ - return (FALSE); + return FALSE; } diff --git a/src/NetworkManagerDHCP.h b/src/NetworkManagerDHCP.h index 84d805fc1..4bfc5a766 100644 --- a/src/NetworkManagerDHCP.h +++ b/src/NetworkManagerDHCP.h @@ -24,12 +24,14 @@ #include "../dhcpcd/dhcpcd.h" -int nm_device_dhcp_request (NMDevice *dev); void nm_device_dhcp_cease (NMDevice *dev); gboolean nm_device_dhcp_setup_timeouts (NMDevice *dev); void nm_device_dhcp_remove_timeouts(NMDevice *dev); gboolean nm_device_dhcp_renew (gpointer user_data); gboolean nm_device_dhcp_rebind (gpointer user_data); -gboolean nm_device_do_autoip (NMDevice *dev); + + +NMIP4Config * nm_device_new_ip4_autoip_config (NMDevice *dev); +NMIP4Config * nm_device_new_ip4_dhcp_config (NMDevice *dev); #endif diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c index e3812877f..923c3feb1 100644 --- a/src/NetworkManagerDbus.c +++ b/src/NetworkManagerDbus.c @@ -40,6 +40,7 @@ #include "nm-dbus-device.h" #include "nm-dbus-net.h" #include "nm-dbus-dhcp.h" +#include "nm-dbus-vpn.h" #include "nm-utils.h" @@ -201,7 +202,6 @@ void nm_dbus_schedule_network_not_found_signal (NMData *data, const char *networ } - /*-------------------------------------------------------------*/ /* Handler code */ /*-------------------------------------------------------------*/ @@ -459,7 +459,7 @@ void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevic message = dbus_message_new_signal (NM_DBUS_PATH, NM_DBUS_INTERFACE, "WirelessNetworkUpdate"); if (!message) { - nm_warning ("nm_dbus_signal_wireless_network_appeared(): Not enough memory for new dbus message!"); + nm_warning ("nm_dbus_signal_wireless_network_change(): Not enough memory for new dbus message!"); g_free (dev_path); g_free (ap_path); return; @@ -478,7 +478,7 @@ void nm_dbus_signal_wireless_network_change (DBusConnection *connection, NMDevic dbus_message_append_args (message, DBUS_TYPE_INT32, &strength, DBUS_TYPE_INVALID); if (!dbus_connection_send (connection, message, NULL)) - nm_warning ("nnm_dbus_signal_wireless_network_appeared(): Could not raise the WirelessNetworkAppeared signal!"); + nm_warning ("nm_dbus_signal_wireless_network_change(): Could not raise the WirelessNetworkAppeared signal!"); dbus_message_unref (message); } @@ -952,12 +952,12 @@ gboolean nm_dbus_nmi_is_running (DBusConnection *connection) /* - * nm_dbus_nmi_filter + * nm_dbus_signal_filter * * Respond to NetworkManagerInfo signals about changing Allowed Networks * */ -static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMessage *message, void *user_data) +static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { NMData *data = (NMData *)user_data; const char *object_path; @@ -990,26 +990,53 @@ static DBusHandlerResult nm_dbus_nmi_filter (DBusConnection *connection, DBusMes handled = TRUE; } } + else if ( (strcmp (object_path, NMI_DBUS_PATH) == 0) + && dbus_message_is_signal (message, NMI_DBUS_INTERFACE, "VPNConnectionUpdate")) + { + char *name = NULL; + + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + { + NMVPNConnection *vpn; + + /* Update a single VPN connection's data */ + nm_debug ("NetworkManagerInfo triggered update of VPN connection '%s'", name); + vpn = nm_dbus_vpn_add_one_connection (data->dbus_connection, name, data->vpn_manager); + if (vpn) + nm_dbus_vpn_signal_vpn_connection_update (data->dbus_connection, vpn); + handled = TRUE; + } + } else if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { char *service; char *old_owner; char *new_owner; - if ( dbus_message_get_args (message, &error, - DBUS_TYPE_STRING, &service, - DBUS_TYPE_STRING, &old_owner, - DBUS_TYPE_STRING, &new_owner, - DBUS_TYPE_INVALID) - && (strcmp (service, NMI_DBUS_SERVICE) == 0)) + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &service, DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID)) { - gboolean old_owner_good = (old_owner && (strlen (old_owner) > 0)); - gboolean new_owner_good = (new_owner && (strlen (new_owner) > 0)); + if (strcmp (service, NMI_DBUS_SERVICE) == 0) + { + gboolean old_owner_good = (old_owner && (strlen (old_owner) > 0)); + gboolean new_owner_good = (new_owner && (strlen (new_owner) > 0)); - if (!old_owner_good && new_owner_good) - nm_policy_schedule_allowed_ap_list_update (data); + if (!old_owner_good && new_owner_good) /* NMI just appeared */ + { + nm_policy_schedule_allowed_ap_list_update (data); + nm_dbus_vpn_schedule_vpn_connections_update (data); + } + } + else if (nm_vpn_manager_process_name_owner_changed (data->vpn_manager, service, old_owner, new_owner) == TRUE) + { + /* Processed by the VPN manager */ + } } } + else if (nm_vpn_manager_process_signal (data->vpn_manager, message) == TRUE) + { + /* Processed by the VPN manager */ + } if (dbus_error_is_set (&error)) dbus_error_free (&error); @@ -1070,10 +1097,7 @@ static DBusHandlerResult nm_dbus_devices_message_handler (DBusConnection *connec path = dbus_message_get_path (message); if (!(dev = nm_dbus_get_device_from_object_path (data, path))) - { - reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotFound", - "The requested network device does not exist."); - } + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE, "DeviceNotFound", "The requested network device does not exist."); else { char *object_path, *escaped_object_path; @@ -1139,6 +1163,38 @@ static DBusHandlerResult nm_dbus_dhcp_message_handler (DBusConnection *connectio } +/* + * nm_dbus_vpn_message_handler + * + * Dispatch messages against our NetworkManager VPNConnections object + * + */ +static DBusHandlerResult nm_dbus_vpn_message_handler (DBusConnection *connection, DBusMessage *message, void *user_data) +{ + NMData *data = (NMData *)user_data; + gboolean handled = TRUE; + DBusMessage *reply = NULL; + NMDbusCBData cb_data; + + g_return_val_if_fail (data != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (data->vpn_methods != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + cb_data.data = data; + cb_data.dev = NULL; + cb_data.opt_id = -1; + handled = nm_dbus_method_dispatch (data->vpn_methods, connection, message, &cb_data, &reply); + if (reply) + { + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + } + + return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); +} + + /* * nm_dbus_is_info_daemon_running * @@ -1173,6 +1229,7 @@ DBusConnection *nm_dbus_init (NMData *data) DBusObjectPathVTable nm_vtable = {NULL, &nm_dbus_nm_message_handler, NULL, NULL, NULL, NULL}; DBusObjectPathVTable devices_vtable = {NULL, &nm_dbus_devices_message_handler, NULL, NULL, NULL, NULL}; DBusObjectPathVTable dhcp_vtable = {NULL, &nm_dbus_dhcp_message_handler, NULL, NULL, NULL, NULL}; + DBusObjectPathVTable vpn_vtable = {NULL, &nm_dbus_vpn_message_handler, NULL, NULL, NULL, NULL}; dbus_connection_set_change_sigpipe (TRUE); @@ -1192,17 +1249,19 @@ DBusConnection *nm_dbus_init (NMData *data) data->device_methods = nm_dbus_device_methods_setup (); data->net_methods = nm_dbus_net_methods_setup (); data->dhcp_methods = nm_dbus_dhcp_methods_setup (); + data->vpn_methods = nm_dbus_vpn_methods_setup (); if ( !dbus_connection_register_object_path (connection, NM_DBUS_PATH, &nm_vtable, data) || !dbus_connection_register_fallback (connection, NM_DBUS_PATH_DEVICES, &devices_vtable, data) - || !dbus_connection_register_object_path (connection, NM_DBUS_PATH_DHCP, &dhcp_vtable, data)) + || !dbus_connection_register_object_path (connection, NM_DBUS_PATH_DHCP, &dhcp_vtable, data) + || !dbus_connection_register_object_path (connection, NM_DBUS_PATH_VPN, &vpn_vtable, data)) { nm_error ("nm_dbus_init() could not register D-BUS handlers. Cannot continue."); connection = NULL; goto out; } - if (!dbus_connection_add_filter (connection, nm_dbus_nmi_filter, data, NULL)) + if (!dbus_connection_add_filter (connection, nm_dbus_signal_filter, data, NULL)) { nm_error ("nm_dbus_init() could not attach a dbus message filter. The NetworkManager dbus security policy may not be loaded. Restart dbus?"); connection = NULL; diff --git a/src/NetworkManagerDbus.h b/src/NetworkManagerDbus.h index 9d7805b56..9df3a2313 100644 --- a/src/NetworkManagerDbus.h +++ b/src/NetworkManagerDbus.h @@ -77,4 +77,6 @@ NMDevice * nm_dbus_get_device_from_object_path (NMData *data, const char *path); char * nm_dbus_network_status_from_data (NMData *data); +DBusMessage * nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace, const char *exception, const char *format, ...); + #endif diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 6d6dfdb3f..e1d3e788d 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * (C) Copyright 2004 Red Hat, Inc. + * (C) Copyright 2005 Red Hat, Inc. */ #include @@ -38,7 +38,8 @@ #include "NetworkManagerAPList.h" #include "NetworkManagerSystem.h" #include "NetworkManagerDHCP.h" - +#include "nm-ip4-config.h" +#include "nm-vpn-manager.h" #include "nm-utils.h" /* Local static prototypes */ @@ -289,6 +290,7 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, dev->iface = g_strdup (iface); dev->test_device = test_dev; nm_device_set_udi (dev, udi); + dev->use_dhcp = TRUE; /* Real hardware devices are probed for their type, test devices must have * their type specified. @@ -378,7 +380,7 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, nm_device_update_hw_address (dev); /* Grab IP config data for this device from the system configuration files */ - nm_system_device_update_config_info (dev); + dev->system_config_data = nm_system_device_get_system_config (dev); } if (!g_thread_create (nm_device_worker, dev, FALSE, &error)) @@ -456,6 +458,10 @@ gboolean nm_device_unref (NMDevice *dev) dev->dhcp_iface = NULL; } + nm_system_device_free_system_config (dev, dev->system_config_data); + if (dev->ip4_config) + nm_ip4_config_unref (dev->ip4_config); + g_free (dev->udi); g_free (dev->iface); memset (dev, 0, sizeof (NMDevice)); @@ -503,7 +509,7 @@ static gpointer nm_device_worker (gpointer user_data) g_main_loop_run (dev->loop); /* Remove any DHCP timeouts that might have been running */ - if (nm_device_config_get_use_dhcp (dev)) + if (nm_device_get_use_dhcp (dev)) nm_device_dhcp_remove_timeouts (dev); g_main_loop_unref (dev->loop); @@ -1509,11 +1515,6 @@ void nm_device_update_hw_address (NMDevice *dev) */ static void nm_device_set_up_down (NMDevice *dev, gboolean up) { - struct ifreq ifr; - NMSock *sk; - int err; - guint32 flags = up ? IFF_UP : ~IFF_UP; - g_return_if_fail (dev != NULL); /* Test devices do whatever we tell them to do */ @@ -1523,34 +1524,13 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) return; } - if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) - return; + nm_system_device_set_up_down (dev, up); - /* Get flags already there */ - strcpy (ifr.ifr_name, nm_device_get_iface (dev)); - err = ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr); - if (!err) - { - /* If the interface doesn't have those flags already, - * set them on it. - */ - if ((ifr.ifr_flags^flags) & IFF_UP) - { - ifr.ifr_flags &= ~IFF_UP; - ifr.ifr_flags |= IFF_UP & flags; - if ((err = ioctl (nm_dev_sock_get_fd (sk), SIOCSIFFLAGS, &ifr))) - nm_warning ("nm_device_set_up_down() could not bring device %s %s. errno = %d", nm_device_get_iface (dev), (up ? "up" : "down"), errno ); - } - /* Make sure we have a valid MAC address, some cards reload firmware when they - * are brought up. - */ - if (!nm_ethernet_address_is_valid((struct ether_addr *)dev->hw_addr)) - nm_device_update_hw_address(dev); - } - else - nm_warning ("nm_device_set_up_down() could not get flags for device %s. errno = %d", nm_device_get_iface (dev), errno ); - - nm_dev_sock_close (sk); + /* Make sure we have a valid MAC address, some cards reload firmware when they + * are brought up. + */ + if (!nm_ethernet_address_is_valid ((struct ether_addr *)dev->hw_addr)) + nm_device_update_hw_address (dev); } @@ -2580,51 +2560,48 @@ out: */ static gboolean nm_device_activation_configure_ip (NMDevice *dev, gboolean do_only_autoip) { - gboolean success = FALSE; + NMIP4Config * ip4_config; + gboolean success = FALSE; g_return_val_if_fail (dev != NULL, FALSE); - nm_system_delete_default_route (); if (do_only_autoip) - { - success = nm_device_do_autoip (dev); - } - else if (nm_device_config_get_use_dhcp (dev)) - { - int err; + ip4_config = nm_device_new_ip4_autoip_config (dev); + else if (nm_device_get_use_dhcp (dev)) + ip4_config = nm_device_new_ip4_dhcp_config (dev); + else + ip4_config = nm_system_device_new_ip4_system_config (dev); - err = nm_device_dhcp_request (dev); - if (err == RET_DHCP_BOUND) - success = TRUE; - else + if (ip4_config) + { + /* Set IP4Config on the device */ + nm_device_set_ip4_config (dev, ip4_config); + if ((success = nm_system_device_set_from_ip4_config (dev))) { - /* Interfaces cannot be down if they are the active interface, - * otherwise we cannot use them for scanning or link detection. - */ - if (nm_device_is_wireless (dev)) - { - nm_device_set_essid (dev, ""); - nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); - } + if (do_only_autoip) + nm_system_flush_loopback_routes (); - if (!nm_device_is_up (dev)) - nm_device_bring_up (dev); + nm_device_update_ip4_address (dev); + nm_system_device_add_ip6_link_address (dev); + nm_system_restart_mdns_responder (); } } else { - /* Manually set up the device */ - success = nm_system_device_setup_static_ip4_config (dev); + /* Interfaces cannot be down if they are the active interface, + * otherwise we cannot use them for scanning or link detection. + */ + if (nm_device_is_wireless (dev)) + { + nm_device_set_essid (dev, ""); + nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); + } + + if (!nm_device_is_up (dev)) + nm_device_bring_up (dev); } - if (success) - { - nm_system_device_add_ip6_link_address (dev); - nm_system_flush_arp_cache (); - nm_system_restart_mdns_responder (); - } - - return (success); + return success; } @@ -2792,6 +2769,8 @@ void nm_device_activation_cancel (NMDevice *dev) */ gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added) { + NMIP4Config *config; + g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (dev->app_data != NULL, FALSE); @@ -2801,9 +2780,19 @@ gboolean nm_device_deactivate (NMDevice *dev, gboolean just_added) return (TRUE); /* Remove any DHCP timeouts that might have been running */ - if (nm_device_config_get_use_dhcp (dev)) + if (nm_device_get_use_dhcp (dev)) nm_device_dhcp_remove_timeouts (dev); + nm_vpn_manager_deactivate_vpn_connection (dev->app_data->vpn_manager); + + /* Remove any device nameservers and domains */ + if ((config = nm_device_get_ip4_config (dev))) + { + nm_system_remove_ip4_config_nameservers (dev->app_data->named, config); + nm_system_remove_ip4_config_search_domains (dev->app_data->named, config); + nm_device_set_ip4_config (dev, NULL); + } + /* Take out any entries in the routing table and any IP address the device had. */ nm_system_device_flush_routes (dev); nm_system_device_flush_addresses (dev); @@ -3825,75 +3814,57 @@ reschedule: } -/* System config data accessors */ +/* IP Configuration stuff */ -gboolean nm_device_config_get_use_dhcp (NMDevice *dev) +gboolean nm_device_get_use_dhcp (NMDevice *dev) { - g_return_val_if_fail (dev != NULL, 0); + g_return_val_if_fail (dev != NULL, FALSE); - return (dev->config_info.use_dhcp); + return dev->use_dhcp; } -void nm_device_config_set_use_dhcp (NMDevice *dev, gboolean use_dhcp) +void nm_device_set_use_dhcp (NMDevice *dev, gboolean use_dhcp) { g_return_if_fail (dev != NULL); - dev->config_info.use_dhcp = use_dhcp; + dev->use_dhcp = use_dhcp; } -guint32 nm_device_config_get_ip4_address (NMDevice *dev) -{ - g_return_val_if_fail (dev != NULL, 0); - return (dev->config_info.ip4_address); +NMIP4Config *nm_device_get_ip4_config (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, NULL); + + return dev->ip4_config; } -void nm_device_config_set_ip4_address (NMDevice *dev, guint32 addr) + +void nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config) { + NMIP4Config *old_config; + g_return_if_fail (dev != NULL); - dev->config_info.ip4_address = addr; + old_config = dev->ip4_config; + if (config) + nm_ip4_config_ref (config); + dev->ip4_config = config; + if (old_config) + nm_ip4_config_unref (old_config); } -guint32 nm_device_config_get_ip4_gateway (NMDevice *dev) + +/* + * nm_device_get_system_config_data + * + * Return distro-specific system configuration data for this device. + * + */ +void *nm_device_get_system_config_data (NMDevice *dev) { - g_return_val_if_fail (dev != NULL, 0); + g_return_val_if_fail (dev != NULL, NULL); - return (dev->config_info.ip4_gateway); -} - -void nm_device_config_set_ip4_gateway (NMDevice *dev, guint32 gateway) -{ - g_return_if_fail (dev != NULL); - - dev->config_info.ip4_gateway = gateway; -} - -guint32 nm_device_config_get_ip4_netmask (NMDevice *dev) -{ - g_return_val_if_fail (dev != NULL, 0); - - return (dev->config_info.ip4_netmask); -} - -void nm_device_config_set_ip4_netmask (NMDevice *dev, guint32 netmask) -{ - g_return_if_fail (dev != NULL); - - dev->config_info.ip4_netmask = netmask; -} -guint32 nm_device_config_get_ip4_broadcast (NMDevice *dev) -{ - g_return_val_if_fail (dev != NULL, 0); - - return (dev->config_info.ip4_broadcast); -} - -void nm_device_config_set_ip4_broadcast (NMDevice *dev, guint32 broadcast) -{ - g_return_if_fail (dev != NULL); - - dev->config_info.ip4_broadcast = broadcast; + return dev->system_config_data; } @@ -4008,3 +3979,4 @@ gboolean nm_device_is_test_device (NMDevice *dev) return (dev->test_device); } + diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index 820755f7a..9369f5c6b 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -26,10 +26,12 @@ #include #include "NetworkManager.h" #include "NetworkManagerMain.h" +#include "nm-ip4-config.h" typedef struct NMDevice NMDevice; + NMDevice * nm_device_new (const char *iface, const char *udi, gboolean test_device, NMDeviceType test_dev_type, NMData *app_data); @@ -123,17 +125,13 @@ NMAccessPoint *nm_device_ap_list_get_ap_by_essid (NMDevice *dev, const char *ess NMAccessPoint *nm_device_ap_list_get_ap_by_address(NMDevice *dev, const struct ether_addr *addr); void nm_device_copy_allowed_to_dev_list (NMDevice *dev, struct NMAccessPointList *allowed_list); -/* System config data accessors */ -gboolean nm_device_config_get_use_dhcp (NMDevice *dev); -void nm_device_config_set_use_dhcp (NMDevice *dev, gboolean use_dhcp); -guint32 nm_device_config_get_ip4_address (NMDevice *dev); -void nm_device_config_set_ip4_address (NMDevice *dev, guint32 addr); -guint32 nm_device_config_get_ip4_gateway (NMDevice *dev); -void nm_device_config_set_ip4_gateway (NMDevice *dev, guint32 gateway); -guint32 nm_device_config_get_ip4_netmask (NMDevice *dev); -void nm_device_config_set_ip4_netmask (NMDevice *dev, guint32 netmask); -guint32 nm_device_config_get_ip4_broadcast (NMDevice *dev); -void nm_device_config_set_ip4_broadcast (NMDevice *dev, guint32 broadcast); +gboolean nm_device_get_use_dhcp (NMDevice *dev); +void nm_device_set_use_dhcp (NMDevice *dev, gboolean use_dhcp); + +NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); +void nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config); + +void * nm_device_get_system_config_data (NMDevice *dev); /* Utility routines */ NMDevice * nm_get_device_by_udi (NMData *data, const char *udi); diff --git a/src/NetworkManagerDevicePrivate.h b/src/NetworkManagerDevicePrivate.h index 7f019ffcb..01346cec7 100644 --- a/src/NetworkManagerDevicePrivate.h +++ b/src/NetworkManagerDevicePrivate.h @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * (C) Copyright 2004 Red Hat, Inc. + * (C) Copyright 2005 Red Hat, Inc. */ #include @@ -65,6 +65,7 @@ typedef struct NMDeviceWiredOptions gboolean has_carrier_detect; } NMDeviceWiredOptions; +/* General options structure */ typedef union NMDeviceOptions { NMDeviceWirelessOptions wireless; @@ -72,16 +73,6 @@ typedef union NMDeviceOptions } NMDeviceOptions; -typedef struct NMDeviceConfigInfo -{ - gboolean use_dhcp; - guint32 ip4_gateway; - guint32 ip4_address; - guint32 ip4_netmask; - guint32 ip4_broadcast; - /* FIXME: ip6 stuff */ -} NMDeviceConfigInfo; - /* * NetworkManager device structure */ @@ -101,8 +92,12 @@ struct NMDevice unsigned char hw_addr[ETH_ALEN]; NMData *app_data; NMDeviceOptions options; - NMDeviceConfigInfo config_info; - struct dhcp_interface *dhcp_iface; + + /* IP configuration info */ + void * system_config_data; /* Distro-specific config data (parsed config file, etc) */ + gboolean use_dhcp; + NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */ + struct dhcp_interface * dhcp_iface; GMainContext *context; GMainLoop *loop; diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h index ff3b15084..76a9327f1 100644 --- a/src/NetworkManagerMain.h +++ b/src/NetworkManagerMain.h @@ -32,26 +32,27 @@ #include "nm-named-manager.h" typedef struct NMDbusMethodList NMDbusMethodList; +typedef struct NMVPNManager NMVPNManager; typedef struct NMData { GIOChannel *sigterm_iochannel; - int sigterm_pipe[2]; + int sigterm_pipe[2]; LibHalContext *hal_ctx; NmNetlinkMonitor *netlink_monitor; NMNamedManager *named; - GList *nameserver_ids; /* For now these are global instead of per-device */ - GList *domain_search_ids; + NMVPNManager *vpn_manager; DBusConnection *dbus_connection; NMDbusMethodList *nm_methods; NMDbusMethodList *device_methods; NMDbusMethodList *net_methods; NMDbusMethodList *dhcp_methods; + NMDbusMethodList *vpn_methods; GMainContext *main_context; GMainLoop *main_loop; diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 7fa21ade3..effecc78a 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -516,7 +516,7 @@ static gboolean nm_policy_allowed_ap_list_update (gpointer user_data) else nm_device_copy_allowed_to_dev_list (dev, data->allowed_ap_list); } - } + } /* If the active device doesn't have a best_ap already, make it update to * get the new data. diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 5f849fa42..dfef1645b 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -44,27 +45,288 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" -gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) + + +static gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address); +static gboolean nm_system_device_set_ip4_address_with_iface (NMDevice *dev, const char *iface, int ip4_address); + +static gboolean nm_system_device_set_ip4_ptp_address (NMDevice *dev, int ip4_ptp_address); +static gboolean nm_system_device_set_ip4_ptp_address_with_iface (NMDevice *dev, const char *iface, int ip4_ptp_address); + +static gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask); +static gboolean nm_system_device_set_ip4_netmask_with_iface (NMDevice *dev, const char *iface, int ip4_netmask); + +static gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast); +static gboolean nm_system_device_set_ip4_broadcast_with_iface (NMDevice *dev, const char *iface, int ip4_broadcast); + +static gboolean nm_system_device_set_ip4_route (NMDevice *dev, int ip4_gateway, int ip4_dest, int ip4_netmask); +static gboolean nm_system_device_set_ip4_route_with_iface (NMDevice *dev, const char *iface, int ip4_gateway, int ip4_dest, int ip4_netmask); + + +/* + * nm_system_remove_ip4_config_nameservers + * + * Remove an IPv4 Config's nameservers from the name service. + * + */ +void nm_system_remove_ip4_config_nameservers (NMNamedManager *named, NMIP4Config *config) +{ + GError *error = NULL; + int i, len; + + g_return_if_fail (config != NULL); + + len = nm_ip4_config_get_num_nameservers (config); + for (i = 0; i < len; i++) + { + guint id = nm_ip4_config_get_nameserver_id (config, i); + if ((id != 0) && !nm_named_manager_remove_nameserver_ipv4 (named, id, &error)) + { + nm_warning ("Couldn't remove nameserver: %s", error->message); + g_clear_error (&error); + } + else + nm_ip4_config_set_nameserver_id (config, i, 0); + } +} + + +static void set_nameservers (NMNamedManager *named, NMIP4Config *config) +{ + GError *error = NULL; + int i, len; + + g_return_if_fail (config != NULL); + + len = nm_ip4_config_get_num_nameservers (config); + for (i = 0; i < len; i++) + { + guint id; + guint ns_addr = nm_ip4_config_get_nameserver (config, i); + struct in_addr temp_addr; + char * nameserver; + + temp_addr.s_addr = ns_addr; + nameserver = g_strdup (inet_ntoa (temp_addr)); + nm_info ("Adding nameserver: %s", nameserver); + if ((id = nm_named_manager_add_nameserver_ipv4 (named, nameserver, &error))) + nm_ip4_config_set_nameserver_id (config, i, id); + else + { + nm_warning ("Couldn't add nameserver: %s", error->message); + g_clear_error (&error); + } + g_free (nameserver); + } +} + + +/* + * nm_system_remove_ip4_config_search_domains + * + * Remove an IPv4 Config's search domains from the name service. + * + */ +void nm_system_remove_ip4_config_search_domains (NMNamedManager *named, NMIP4Config *config) +{ + GError *error = NULL; + int i, len; + + g_return_if_fail (config != NULL); + + len = nm_ip4_config_get_num_domains (config); + for (i = 0; i < len; i++) + { + guint id = nm_ip4_config_get_domain_id (config, i); + if ((id != 0) && !nm_named_manager_remove_domain_search (named, id, &error)) + { + nm_warning ("Couldn't remove domain search: %s", error->message); + g_clear_error (&error); + } + else + nm_ip4_config_set_domain_id (config, i, 0); + } +} + +static void set_search_domains (NMNamedManager *named, NMIP4Config *config) +{ + GError *error = NULL; + int i, len; + + g_return_if_fail (config != NULL); + + len = nm_ip4_config_get_num_domains (config); + for (i = 0; i < len; i++) + { + const char * domain = nm_ip4_config_get_domain (config, i); + guint id; + + nm_info ("Adding domain search: %s", domain); + if ((id = nm_named_manager_add_domain_search (named, domain, &error))) + nm_ip4_config_set_domain_id (config, i, id); + else + { + nm_warning ("Couldn't add domain search: %s", error->message); + g_clear_error (&error); + } + } +} + + +/* + * nm_system_device_set_from_ip4_config + * + * Set IPv4 configuration of the device from an NMIP4Config object. + * + */ +gboolean nm_system_device_set_from_ip4_config (NMDevice *dev) +{ + NMData * app_data; + NMIP4Config * config; + gboolean success = FALSE; + + g_return_val_if_fail (dev != NULL, FALSE); + + app_data = nm_device_get_app_data (dev); + g_return_val_if_fail (app_data != NULL, FALSE); + + config = nm_device_get_ip4_config (dev); + g_return_val_if_fail (config != NULL, FALSE); + + nm_system_delete_default_route (); + nm_system_device_flush_addresses (dev); + nm_system_device_flush_routes (dev); + nm_system_flush_arp_cache (); + + nm_system_device_set_ip4_address (dev, nm_ip4_config_get_address (config)); + nm_system_device_set_ip4_netmask (dev, nm_ip4_config_get_netmask (config)); + nm_system_device_set_ip4_broadcast (dev, nm_ip4_config_get_broadcast (config)); + sleep (1); + nm_system_device_set_ip4_route (dev, nm_ip4_config_get_gateway (config), 0, 0); + + set_nameservers (app_data->named, config); + set_search_domains (app_data->named, config); + + return TRUE; +} + + +/* + * nm_system_vpn_device_set_from_ip4_config + * + * Set IPv4 configuration of a VPN device from an NMIP4Config object. + * + */ +gboolean nm_system_vpn_device_set_from_ip4_config (NMNamedManager *named, NMDevice *active_device, const char *iface, NMIP4Config *config) +{ + gboolean success = FALSE; + NMIP4Config * ad_config = NULL; + + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (config != NULL, FALSE); + + if (active_device && (ad_config = nm_device_get_ip4_config (active_device))) + { + nm_system_remove_ip4_config_nameservers (named, ad_config); + nm_system_remove_ip4_config_search_domains (named, ad_config); + nm_system_device_set_ip4_route (active_device, nm_ip4_config_get_gateway (ad_config), nm_ip4_config_get_gateway (config), 0xFFFFFFFF); + } + + nm_system_device_set_up_down_with_iface (NULL, iface, TRUE); + + nm_system_device_set_ip4_address_with_iface (NULL, iface, nm_ip4_config_get_address (config)); + nm_system_device_set_ip4_ptp_address_with_iface (NULL, iface, nm_ip4_config_get_address (config)); + nm_system_device_set_ip4_netmask_with_iface (NULL, iface, nm_ip4_config_get_netmask (config)); + sleep (1); + nm_system_delete_default_route (); + nm_system_device_flush_routes_with_iface (iface); + nm_system_device_add_default_route_via_device_with_iface (iface); + + set_nameservers (named, config); + set_search_domains (named, config); + + return TRUE; +} + + +/* + * nm_system_device_set_up_down + * + * Mark the device as up or down. + * + */ +gboolean nm_system_device_set_up_down (NMDevice *dev, gboolean up) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return nm_system_device_set_up_down_with_iface (dev, nm_device_get_iface (dev), up); +} + +gboolean nm_system_device_set_up_down_with_iface (NMDevice *dev, const char *iface, gboolean up) +{ + struct ifreq ifr; + guint32 flags = up ? IFF_UP : ~IFF_UP; + NMSock * sk; + gboolean success = FALSE; + + g_return_val_if_fail (iface != NULL, FALSE); + + if ((sk = nm_dev_sock_open (dev, DEV_GENERAL, __FUNCTION__, NULL)) == NULL) + return FALSE; + + /* Get flags already there */ + memset (&ifr, 0, sizeof (struct ifreq)); + memcpy (ifr.ifr_name, iface, strlen (iface)); + if (!ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr)) + { + /* If the interface doesn't have those flags already, set them on it. */ + if ((ifr.ifr_flags^flags) & IFF_UP) + { + ifr.ifr_flags &= ~IFF_UP; + ifr.ifr_flags |= IFF_UP & flags; + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFFLAGS, &ifr)) + nm_warning ("nm_system_device_set_up_down_with_iface() could not bring device %s %s. errno = %d", iface, (up ? "up" : "down"), errno); + } + } + else + nm_warning ("nm_system_device_set_up_down_with_iface() could not get flags for device %s. errno = %d", iface, errno ); + + nm_dev_sock_close (sk); + return success; +} + + +/* + * nm_system_device_set_ip4_address + * + * Set the device's IPv4 address. + * + */ +static gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return nm_system_device_set_ip4_address_with_iface (dev, nm_device_get_iface (dev), ip4_address); +} + +static gboolean nm_system_device_set_ip4_address_with_iface (NMDevice *dev, const char *iface, int ip4_address) { struct ifreq ifr; - const char *iface; NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); - g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (iface != NULL, FALSE); if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; - memset (&ifr, 0, sizeof(struct ifreq)); - - iface = nm_device_get_iface (dev); + memset (&ifr, 0, sizeof (struct ifreq)); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_address; if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFADDR, &ifr) == -1) - nm_warning ("nm_system_device_set_ip4_address (%s): failed to set IPv4 address!", iface); + nm_warning ("nm_system_device_set_ip4_address_by_iface (%s): failed to set IPv4 address!", iface); else { success = TRUE; @@ -78,22 +340,94 @@ gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) } -gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) +/* + * nm_system_device_set_ip4_ptp_address + * + * Set the device's IPv4 point-to-point address. + * + */ +static gboolean nm_system_device_set_ip4_ptp_address (NMDevice *dev, int ip4_ptp_address) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return nm_system_device_set_ip4_ptp_address_with_iface (dev, nm_device_get_iface (dev), ip4_ptp_address); +} + +static gboolean nm_system_device_set_ip4_ptp_address_with_iface (NMDevice *dev, const char *iface, int ip4_ptp_address) { struct ifreq ifr; - const char *iface; NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); - g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (iface != NULL, FALSE); if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; - memset (&ifr, 0, sizeof(struct ifreq)); + memset (&ifr, 0, sizeof (struct ifreq)); + memcpy (ifr.ifr_name, iface, strlen (iface)); + p->sin_family = AF_INET; + p->sin_port = 0; + p->sin_addr.s_addr = ip4_ptp_address; - iface = nm_device_get_iface (dev); + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFDSTADDR, &ifr) == -1) + nm_warning ("nm_system_device_set_ip4_ptp_address (%s): failed to set IPv4 point-to-point address!", iface); + else + { + struct ifreq ifr2; + + memset (&ifr2, 0, sizeof (struct ifreq)); + memcpy (ifr2.ifr_name, iface, strlen (iface)); + if (ioctl (nm_dev_sock_get_fd (sk), SIOCGIFFLAGS, &ifr2) >= 0) + { + memcpy (ifr2.ifr_name, iface, strlen (iface)); + ifr2.ifr_flags |= IFF_POINTOPOINT; + if (ioctl (nm_dev_sock_get_fd (sk), SIOCSIFFLAGS, &ifr2) >= 0) + { + success = TRUE; + nm_info ("Your Point-to-Point IP address = %u.%u.%u.%u", + ((unsigned char *)&ip4_ptp_address)[0], ((unsigned char *)&ip4_ptp_address)[1], + ((unsigned char *)&ip4_ptp_address)[2], ((unsigned char *)&ip4_ptp_address)[3]); + } + else + nm_warning ("nm_system_device_set_ip4_ptp_address (%s): failed to set POINTOPOINT flag on device!", iface); + } + else + nm_warning ("nm_system_device_set_ip4_ptp_address (%s): failed to get interface flags!", iface); + } + + nm_dev_sock_close (sk); + return (success); +} + + +/* + * nm_system_device_set_ip4_netmask + * + * Set the IPv4 netmask on a device. + * + */ +static gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return nm_system_device_set_ip4_netmask_with_iface (dev, nm_device_get_iface (dev), ip4_netmask); +} + +static gboolean nm_system_device_set_ip4_netmask_with_iface (NMDevice *dev, const char *iface, int ip4_netmask) +{ + struct ifreq ifr; + NMSock *sk; + gboolean success = FALSE; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + g_return_val_if_fail (iface != NULL, FALSE); + + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) + return FALSE; + + memset (&ifr, 0, sizeof (struct ifreq)); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_netmask; @@ -107,21 +441,32 @@ gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) } -gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) +/* + * nm_system_device_set_ip4_broadcast + * + * Set the IPv4 broadcast address on a device. + * + */ +static gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return nm_system_device_set_ip4_broadcast_with_iface (dev, nm_device_get_iface (dev), ip4_broadcast); +} + +static gboolean nm_system_device_set_ip4_broadcast_with_iface (NMDevice *dev, const char *iface, int ip4_broadcast) { struct ifreq ifr; - const char *iface; NMSock *sk; gboolean success = FALSE; struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); - g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (iface != NULL, FALSE); if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; memset (&ifr, 0, sizeof(struct ifreq)); - iface = nm_device_get_iface (dev); memcpy (ifr.ifr_name, iface, strlen (iface)); p->sin_family = AF_INET; p->sin_addr.s_addr = ip4_broadcast; @@ -135,48 +480,58 @@ gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) } -gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route) +/* + * nm_system_device_set_ip4_broadcast + * + * Set the IPv4 broadcast address on a device. + * + */ +static gboolean nm_system_device_set_ip4_route (NMDevice *dev, int ip4_gateway, int ip4_dest, int ip4_netmask) { - const char *iface; - NMSock *sk; - gboolean success = FALSE; - struct rtentry rtent; - struct sockaddr_in *p; - g_return_val_if_fail (dev != NULL, FALSE); + return nm_system_device_set_ip4_route_with_iface (dev, nm_device_get_iface (dev), ip4_gateway, ip4_dest, ip4_netmask); +} + +static gboolean nm_system_device_set_ip4_route_with_iface (NMDevice *dev, const char *iface, int ip4_gateway, int ip4_dest, int ip4_netmask) +{ + NMSock * sk; + gboolean success = FALSE; + struct rtentry rtent; + struct sockaddr_in *p; + + g_return_val_if_fail (iface != NULL, FALSE); + if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL) return FALSE; - iface = nm_device_get_iface (dev); - memset (&rtent, 0, sizeof (struct rtentry)); p = (struct sockaddr_in *)&rtent.rt_dst; p->sin_family = AF_INET; - p->sin_addr.s_addr = 0; + p->sin_addr.s_addr = ip4_dest; p = (struct sockaddr_in *)&rtent.rt_gateway; p->sin_family = AF_INET; - p->sin_addr.s_addr = ip4_def_route; + p->sin_addr.s_addr = ip4_gateway; p = (struct sockaddr_in *)&rtent.rt_genmask; p->sin_family = AF_INET; - p->sin_addr.s_addr = 0; + p->sin_addr.s_addr = ip4_netmask; rtent.rt_dev = (char *)iface; rtent.rt_metric = 1; rtent.rt_window = 0; - rtent.rt_flags = RTF_UP | RTF_GATEWAY | ( rtent.rt_window ? RTF_WINDOW : 0); + rtent.rt_flags = RTF_UP | RTF_GATEWAY | (rtent.rt_window ? RTF_WINDOW : 0); if (ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent) == -1) { - if (errno == ENETUNREACH) /* possibly gateway is over the bridge */ - { /* try adding a route to gateway first */ - struct rtentry rtent2; + if (errno == ENETUNREACH) /* possibly gateway is over the bridge */ + { /* try adding a route to gateway first */ + struct rtentry rtent2; memset (&rtent2, 0, sizeof(struct rtentry)); p = (struct sockaddr_in *)&rtent2.rt_dst; p->sin_family = AF_INET; p = (struct sockaddr_in *)&rtent2.rt_gateway; p->sin_family = AF_INET; - p->sin_addr.s_addr = ip4_def_route; + p->sin_addr.s_addr = ip4_gateway; p = (struct sockaddr_in *)&rtent2.rt_genmask; p->sin_family = AF_INET; p->sin_addr.s_addr = 0xffffffff; diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index 560487146..3aad32551 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -32,10 +32,16 @@ void nm_system_init (void); gboolean nm_system_device_has_active_routes (NMDevice *dev); + void nm_system_device_flush_routes (NMDevice *dev); +void nm_system_device_flush_routes_with_iface (const char *iface); + void nm_system_device_add_default_route_via_device(NMDevice *dev); +void nm_system_device_add_default_route_via_device_with_iface(const char *iface); + void nm_system_device_flush_addresses (NMDevice *dev); -void nm_system_device_update_config_info (NMDevice *dev); +void nm_system_device_flush_addresses_with_iface (const char *iface); + gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev); void nm_system_enable_loopback (void); void nm_system_flush_loopback_routes (void); @@ -47,11 +53,22 @@ void nm_system_load_device_modules (void); void nm_system_restart_mdns_responder (void); void nm_system_device_add_ip6_link_address (NMDevice *dev); -/* Prototyps for system-layer network functions (ie setting IP address, etc) */ -gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address); -gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask); -gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast); -gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route); +void * nm_system_device_get_system_config (NMDevice *dev); +void nm_system_device_free_system_config (NMDevice *dev, void *system_config_data); +NMIP4Config * nm_system_device_new_ip4_system_config (NMDevice *dev); + +gboolean nm_system_device_get_use_dhcp (NMDevice *dev); + +/* Prototypes for system-layer network functions (ie setting IP address, etc) */ +void nm_system_remove_ip4_config_nameservers (NMNamedManager *named, NMIP4Config *config); +void nm_system_remove_ip4_config_search_domains (NMNamedManager *named, NMIP4Config *config); + +gboolean nm_system_device_set_from_ip4_config (NMDevice *dev); +gboolean nm_system_vpn_device_set_from_ip4_config (NMNamedManager *named, NMDevice *active_device, const char *iface, NMIP4Config *config); + +gboolean nm_system_device_set_up_down (NMDevice *dev, gboolean up); +gboolean nm_system_device_set_up_down_with_iface (NMDevice *dev, const char *iface, gboolean up); + gboolean nm_system_device_update_resolv_conf (void *data, int len, const char *domain_name); #endif diff --git a/src/backends/.cvsignore b/src/backends/.cvsignore index 0638d7514..46cd0498a 100644 --- a/src/backends/.cvsignore +++ b/src/backends/.cvsignore @@ -1 +1,3 @@ .dirstamp +Makefile +Makefile.in diff --git a/src/backends/Makefile.am b/src/backends/Makefile.am new file mode 100644 index 000000000..c41caeaf1 --- /dev/null +++ b/src/backends/Makefile.am @@ -0,0 +1,30 @@ +INCLUDES = -I${top_srcdir} -I./named-manager -I./vpn-manager -I${top_srcdir}/utils + +noinst_LTLIBRARIES = libnmbackend.la + +libnmbackend_la_SOURCES = + +if TARGET_REDHAT +libnmbackend_la_SOURCES += NetworkManagerRedHat.c \ + shvar.c \ + shvar.h +endif + +if TARGET_GENTOO +libnmbackend_la_SOURCES += NetworkManagerGentoo.c +endif + +if TARGET_DEBIAN +libnmbackend_la_SOURCES += NetworkManagerDebian.c \ + interface_parser.c \ + interface_parser.h +endif + +if TARGET_SLACKWARE +libnmbackend_la_SOURCES += NetworkManagerSlackware.c +endif + +libnmbackend_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) +libnmbackend_la_CFLAGS = $(NetworkManager_CPPFLAGS) + + diff --git a/src/backends/NetworkManagerRedHat.c b/src/backends/NetworkManagerRedHat.c index d7900778f..22f66e5e9 100644 --- a/src/backends/NetworkManagerRedHat.c +++ b/src/backends/NetworkManagerRedHat.c @@ -39,10 +39,6 @@ void nm_system_init (void) { /* Kill any dhclients lying around */ nm_system_kill_all_dhcp_daemons (); - - /* Stop nifd since we respawn mDNSResponder ourselves */ - if (nm_spawn_process ("/etc/init.d/nifd status") != 0) - nm_spawn_process ("/etc/init.d/nifd stop"); } @@ -54,16 +50,30 @@ void nm_system_init (void) */ void nm_system_device_flush_routes (NMDevice *dev) { - char *buf; - g_return_if_fail (dev != NULL); /* Not really applicable for test devices */ if (nm_device_is_test_device (dev)) return; + nm_system_device_flush_routes_with_iface (nm_device_get_iface (dev)); +} + + +/* + * nm_system_device_flush_routes_with_iface + * + * Flush all routes associated with a network device + * + */ +void nm_system_device_flush_routes_with_iface (const char *iface) +{ + char *buf; + + g_return_if_fail (iface != NULL); + /* Remove routing table entries */ - buf = g_strdup_printf ("/sbin/ip route flush dev %s", nm_device_get_iface (dev)); + buf = g_strdup_printf ("/sbin/ip route flush dev %s", iface); nm_spawn_process (buf); g_free (buf); } @@ -72,21 +82,35 @@ void nm_system_device_flush_routes (NMDevice *dev) /* * nm_system_device_add_default_route_via_device * - * Flush all routes associated with a network device + * Add default route to the given device * */ void nm_system_device_add_default_route_via_device (NMDevice *dev) { - char *buf; - g_return_if_fail (dev != NULL); /* Not really applicable for test devices */ if (nm_device_is_test_device (dev)) return; - /* Remove routing table entries */ - buf = g_strdup_printf ("/sbin/ip route add default dev %s", nm_device_get_iface (dev)); + nm_system_device_add_default_route_via_device_with_iface (nm_device_get_iface (dev)); +} + + +/* + * nm_system_device_add_default_route_via_device_with_iface + * + * Add default route to the given device + * + */ +void nm_system_device_add_default_route_via_device_with_iface (const char *iface) +{ + char *buf; + + g_return_if_fail (iface != NULL); + + /* Add default gateway */ + buf = g_strdup_printf ("/sbin/ip route add default dev %s", iface); nm_spawn_process (buf); g_free (buf); } @@ -113,82 +137,36 @@ gboolean nm_system_device_has_active_routes (NMDevice *dev) */ void nm_system_device_flush_addresses (NMDevice *dev) { - char *buf; - g_return_if_fail (dev != NULL); /* Not really applicable for test devices */ if (nm_device_is_test_device (dev)) return; + nm_system_device_flush_addresses_with_iface (nm_device_get_iface (dev)); +} + + +/* + * nm_system_device_flush_addresses_with_iface + * + * Flush all network addresses associated with a network device + * + */ +void nm_system_device_flush_addresses_with_iface (const char *iface) +{ + char *buf; + + g_return_if_fail (iface != NULL); + /* Remove all IP addresses for a device */ - buf = g_strdup_printf ("/sbin/ip address flush dev %s", nm_device_get_iface (dev)); + buf = g_strdup_printf ("/sbin/ip address flush dev %s", iface); nm_spawn_process (buf); g_free (buf); } -/* - * nm_system_device_setup_static_ip4_config - * - * Set up the device with a particular IPv4 address/netmask/gateway. - * - * Returns: TRUE on success - * FALSE on error - * - */ -gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev) -{ -#define IPBITS (sizeof (guint32) * 8) - struct in_addr temp_addr; - struct in_addr temp_addr2; - char *s_tmp; - char *s_tmp2; - int i; - guint32 addr; - guint32 netmask; - guint32 prefix = IPBITS; /* initialize with # bits in ip4 address */ - guint32 broadcast; - char *buf; - int err; - const char *iface; - - g_return_val_if_fail (dev != NULL, FALSE); - g_return_val_if_fail (!nm_device_config_get_use_dhcp (dev), FALSE); - - addr = nm_device_config_get_ip4_address (dev); - netmask = nm_device_config_get_ip4_netmask (dev); - iface = nm_device_get_iface (dev); - broadcast = nm_device_config_get_ip4_broadcast (dev); - - /* Calculate the prefix (# bits stripped off by the netmask) */ - for (i = 0; i < IPBITS; i++) - { - if (!(ntohl (netmask) & ((2 << i) - 1))) - prefix--; - } - - /* Calculate the broadcast address if the user didn't specify one */ - if (!broadcast) - broadcast = ((addr & (int)netmask) | ~(int)netmask); - - /* FIXME: what if some other device is already using our IP address? */ - - /* Set our IP address */ - temp_addr.s_addr = addr; - temp_addr2.s_addr = broadcast; - s_tmp = g_strdup (inet_ntoa (temp_addr)); - s_tmp2 = g_strdup (inet_ntoa (temp_addr2)); - buf = g_strdup_printf ("/sbin/ip addr add %s/%d brd %s dev %s label %s", s_tmp, prefix, s_tmp2, iface, iface); - g_free (s_tmp); - g_free (s_tmp2); - if ((err = nm_spawn_process (buf))) - { - nm_warning ("Error: could not set network configuration for device '%s' using command:\n '%s'", iface, buf); - goto error; - } - g_free (buf); - +#if 0 /* Alert other computers of our new address */ temp_addr.s_addr = addr; buf = g_strdup_printf ("/sbin/arping -q -A -c 1 -I %s %s", iface, inet_ntoa (temp_addr)); @@ -198,24 +176,7 @@ gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev) buf = g_strdup_printf ("/sbin/arping -q -U -c 1 -I %s %s", iface, inet_ntoa (temp_addr)); nm_spawn_process (buf); g_free (buf); - - /* Set the default route to be this device's gateway */ - temp_addr.s_addr = nm_device_config_get_ip4_gateway (dev); - buf = g_strdup_printf ("/sbin/ip route replace default via %s dev %s", inet_ntoa (temp_addr), iface); - if ((err = nm_spawn_process (buf))) - { - nm_warning ("Error: could not set default route using command\n '%s'", buf); - goto error; - } - g_free (buf); - return (TRUE); - -error: - g_free (buf); - nm_system_device_flush_addresses (dev); - nm_system_device_flush_routes (dev); - return (FALSE); -} +#endif /* @@ -294,7 +255,7 @@ void nm_system_update_dns (void) if (nm_spawn_process ("/etc/init.d/nscd status") != 0) nm_spawn_process ("/etc/init.d/nscd restart"); - nm_warning ("Clearing nscd hosts cache."); + nm_info ("Clearing nscd hosts cache."); nm_spawn_process ("/usr/sbin/nscd -i hosts"); #else nm_spawn_process ("/usr/bin/killall -q nscd"); @@ -368,47 +329,44 @@ void nm_system_device_add_ip6_link_address (NMDevice *dev) } +typedef struct RHSystemConfigData +{ + NMIP4Config * config; + gboolean use_dhcp; +} RHSystemConfigData; + /* - * nm_system_device_update_config_info + * nm_system_device_get_system_config * - * Retrieve any relevant configuration info for a particular device - * from the system network configuration information. Clear out existing - * info before setting stuff too. + * Read in the config file for a device. * */ -void nm_system_device_update_config_info (NMDevice *dev) +void *nm_system_device_get_system_config (NMDevice *dev) { - char *cfg_file_path = NULL; - shvarFile *file; - char *buf = NULL; - gboolean use_dhcp = TRUE; - guint32 ip4_address = 0; - guint32 ip4_netmask = 0; - guint32 ip4_gateway = 0; - guint32 ip4_broadcast = 0; + char * cfg_file_path = NULL; + shvarFile * file; + char * buf = NULL; + RHSystemConfigData * sys_data = NULL; + gboolean error = FALSE; - g_return_if_fail (dev != NULL); - - /* We use DHCP on an interface unless told not to */ - nm_device_config_set_use_dhcp (dev, TRUE); - nm_device_config_set_ip4_address (dev, 0); - nm_device_config_set_ip4_gateway (dev, 0); - nm_device_config_set_ip4_netmask (dev, 0); - nm_device_config_set_ip4_broadcast (dev, 0); + g_return_val_if_fail (dev != NULL, NULL); /* Red Hat/Fedora Core systems store this information in * /etc/sysconfig/network-scripts/ifcfg-* where * is the interface * name. */ + sys_data = g_malloc0 (sizeof (RHSystemConfigData)); + sys_data->use_dhcp = TRUE; + cfg_file_path = g_strdup_printf ("/etc/sysconfig/network-scripts/ifcfg-%s", nm_device_get_iface (dev)); if (!cfg_file_path) - return; + return sys_data; if (!(file = svNewFile (cfg_file_path))) { g_free (cfg_file_path); - return; + return sys_data; } g_free (cfg_file_path); @@ -420,82 +378,148 @@ void nm_system_device_update_config_info (NMDevice *dev) goto out; } - buf = svGetValue (file, "BOOTPROTO"); - if (buf) + if ((buf = svGetValue (file, "BOOTPROTO"))) { - if (strcmp (buf, "dhcp")) - use_dhcp = FALSE; + if (strcasecmp (buf, "dhcp")) + sys_data->use_dhcp = FALSE; free (buf); } - buf = svGetValue (file, "IPADDR"); - if (buf) - { - ip4_address = inet_addr (buf); - free (buf); - } + sys_data->config = nm_ip4_config_new (); - buf = svGetValue (file, "GATEWAY"); - if (buf) + if (!(sys_data->use_dhcp)) { - ip4_gateway = inet_addr (buf); - free (buf); - } - - buf = svGetValue (file, "NETMASK"); - if (buf) - { - ip4_netmask = inet_addr (buf); - free (buf); - } - else - { - /* Make a default netmask if we have an IP address */ - if (ip4_address) + if ((buf = svGetValue (file, "IPADDR"))) { - if (((ntohl (ip4_address) & 0xFF000000) >> 24) <= 127) - ip4_netmask = htonl (0xFF000000); - else if (((ntohl (ip4_address) & 0xFF000000) >> 24) <= 191) - ip4_netmask = htonl (0xFFFF0000); + nm_ip4_config_set_address (sys_data->config, inet_addr (buf)); + free (buf); + } + else + { + nm_warning ("Network configuration for device '%s' was invalid (non-DHCP configuration, " + "but no IP address specified. Will use DHCP instead.", nm_device_get_iface (dev)); + error = TRUE; + goto out; + } + + if ((buf = svGetValue (file, "GATEWAY"))) + { + nm_ip4_config_set_gateway (sys_data->config, inet_addr (buf)); + free (buf); + } + else + { + nm_warning ("Network configuration for device '%s' was invalid (non-DHCP configuration, " + "but no gateway specified. Will use DHCP instead.", nm_device_get_iface (dev)); + error = TRUE; + goto out; + } + + if ((buf = svGetValue (file, "NETMASK"))) + { + nm_ip4_config_set_netmask (sys_data->config, inet_addr (buf)); + free (buf); + } + else + { + guint32 addr = nm_ip4_config_get_address (sys_data->config); + + /* Make a default netmask if we have an IP address */ + if (((ntohl (addr) & 0xFF000000) >> 24) <= 127) + nm_ip4_config_set_netmask (sys_data->config, htonl (0xFF000000)); + else if (((ntohl (addr) & 0xFF000000) >> 24) <= 191) + nm_ip4_config_set_netmask (sys_data->config, htonl (0xFFFF0000)); else - ip4_netmask = htonl (0xFFFFFF00); + nm_ip4_config_set_netmask (sys_data->config, htonl (0xFFFFFF00)); + } + + if ((buf = svGetValue (file, "BROADCAST"))) + { + nm_ip4_config_set_broadcast (sys_data->config, inet_addr (buf)); + free (buf); + } + else + { + guint32 broadcast = ((nm_ip4_config_get_address (sys_data->config) & nm_ip4_config_get_netmask (sys_data->config)) + | ~nm_ip4_config_get_netmask (sys_data->config)); + nm_ip4_config_set_broadcast (sys_data->config, broadcast); } } - buf = svGetValue (file, "BROADCAST"); - if (buf) - { - ip4_broadcast = inet_addr (buf); - free (buf); - } - - if (!use_dhcp && (!ip4_address || !ip4_gateway || !ip4_netmask)) - { - nm_warning ("Error: network configuration for device '%s' was invalid (non-DCHP configuration," - " but no address/gateway specificed). Will use DHCP instead.\n", nm_device_get_iface (dev)); - use_dhcp = TRUE; - } - - /* If successful, set values on the device */ - nm_device_config_set_use_dhcp (dev, use_dhcp); - if (ip4_address) - nm_device_config_set_ip4_address (dev, ip4_address); - if (ip4_gateway) - nm_device_config_set_ip4_gateway (dev, ip4_gateway); - if (ip4_netmask) - nm_device_config_set_ip4_netmask (dev, ip4_netmask); - if (ip4_broadcast) - nm_device_config_set_ip4_broadcast (dev, ip4_broadcast); - #if 0 nm_debug ("------ Config (%s)", nm_device_get_iface (dev)); - nm_debug (" DHCP=%d\n", use_dhcp); - nm_debug (" ADDR=%d\n", ip4_address); - nm_debug (" GW=%d\n", ip4_gateway); - nm_debug (" NM=%d\n", ip4_netmask); + nm_debug (" DHCP=%d\n", sys_data->use_dhcp); + nm_debug (" ADDR=%d\n", nm_ip4_config_get_address (sys_data->config)); + nm_debug (" GW=%d\n", nm_ip4_config_get_gateway (sys_data->config)); + nm_debug (" NM=%d\n", nm_ip4_config_get_netmask (sys_data->config)); nm_debug ("---------------------\n"); #endif out: svCloseFile (file); + + if (error) + { + sys_data->use_dhcp = TRUE; + /* Clear out the config */ + nm_ip4_config_unref (sys_data->config); + sys_data->config = NULL; + } + + return (void *)sys_data; } + + +/* + * nm_system_device_free_system_config + * + * Free stored system config data + * + */ +void nm_system_device_free_system_config (NMDevice *dev, void *system_config_data) +{ + RHSystemConfigData *sys_data = (RHSystemConfigData *)system_config_data; + + g_return_if_fail (dev != NULL); + + if (!sys_data) + return; + + if (sys_data->config) + nm_ip4_config_unref (sys_data->config); +} + + +/* + * nm_system_device_get_use_dhcp + * + * Return whether the distro-specific system config tells us to use + * dhcp for this device. + * + */ +gboolean nm_system_device_get_use_dhcp (NMDevice *dev) +{ + RHSystemConfigData *sys_data; + + g_return_val_if_fail (dev != NULL, TRUE); + + if ((sys_data = nm_device_get_system_config_data (dev))) + return sys_data->use_dhcp; + + return TRUE; +} + + +NMIP4Config *nm_system_device_new_ip4_system_config (NMDevice *dev) +{ + RHSystemConfigData *sys_data; + NMIP4Config *new_config = NULL; + + g_return_val_if_fail (dev != NULL, NULL); + + if ((sys_data = nm_device_get_system_config_data (dev))) + new_config = nm_ip4_config_copy (sys_data->config); + + return new_config; +} + diff --git a/named/.cvsignore b/src/named-manager/.cvsignore similarity index 100% rename from named/.cvsignore rename to src/named-manager/.cvsignore diff --git a/src/named-manager/Makefile.am b/src/named-manager/Makefile.am new file mode 100644 index 000000000..d62edf8fb --- /dev/null +++ b/src/named-manager/Makefile.am @@ -0,0 +1,14 @@ +namedconf_DATA = named.conf +namedconfdir = $(pkgdatadir) + +EXTRA_DIST = $(namedconf_DATA) + +INCLUDES = -I${top_srcdir}/utils + +noinst_LTLIBRARIES = libnamed-manager.la + +libnamed_manager_la_SOURCES = nm-named-manager.h nm-named-manager.c + +libnamed_manager_la_CPPFLAGS = $(DBUS_CFLAGS) $(GTHREAD_CFLAGS) -DNM_PKGDATADIR=\"$(pkgdatadir)\" -DNM_LOCALSTATEDIR=\"$(localstatedir)\" + +libnamed_manager_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) diff --git a/named/named.conf b/src/named-manager/named.conf similarity index 100% rename from named/named.conf rename to src/named-manager/named.conf diff --git a/named/nm-named-manager.c b/src/named-manager/nm-named-manager.c similarity index 100% rename from named/nm-named-manager.c rename to src/named-manager/nm-named-manager.c diff --git a/named/nm-named-manager.h b/src/named-manager/nm-named-manager.h similarity index 100% rename from named/nm-named-manager.h rename to src/named-manager/nm-named-manager.h diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c new file mode 100644 index 000000000..644cb2ba2 --- /dev/null +++ b/src/nm-ip4-config.c @@ -0,0 +1,307 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + + +#include +#include +#include +#include "NetworkManager.h" +#include "nm-ip4-config.h" + + +typedef struct NamserverID +{ + guint32 ns_address; + guint32 ns_id; +} NameserverID; + +typedef struct DomainID +{ + char * domain; + guint32 domain_id; +} DomainID; + +struct NMIP4Config +{ + guint refcount; + guint32 ip4_address; + guint32 ip4_gateway; + guint32 ip4_netmask; + guint32 ip4_broadcast; + GSList *nameservers; + GSList *domains; +}; + + +static void domain_id_free (DomainID *did); +static void nameserver_id_free (NameserverID *ns); + + +NMIP4Config *nm_ip4_config_new (void) +{ + NMIP4Config *config = g_malloc0 (sizeof (NMIP4Config)); + + config->refcount = 1; + + return config; +} + +NMIP4Config *nm_ip4_config_copy (NMIP4Config *src_config) +{ + NMIP4Config * dst_config; + int i, len; + + g_return_val_if_fail (src_config != NULL, NULL); + + dst_config = g_malloc0 (sizeof (NMIP4Config)); + dst_config->refcount = 1; + + dst_config->ip4_address = nm_ip4_config_get_address (src_config); + dst_config->ip4_gateway = nm_ip4_config_get_gateway (src_config); + dst_config->ip4_netmask = nm_ip4_config_get_netmask (src_config); + dst_config->ip4_broadcast = nm_ip4_config_get_broadcast (src_config); + + len = nm_ip4_config_get_num_nameservers (src_config); + for (i = 0; i < len; i++) + nm_ip4_config_add_nameserver (dst_config, nm_ip4_config_get_nameserver (src_config, i)); + + len = nm_ip4_config_get_num_domains (src_config); + for (i = 0; i < len; i++) + nm_ip4_config_add_domain (dst_config, nm_ip4_config_get_domain (src_config, i)); + + return dst_config; +} + +void nm_ip4_config_ref (NMIP4Config *config) +{ + g_return_if_fail (config != NULL); + + config->refcount++; +} + +void nm_ip4_config_unref (NMIP4Config *config) +{ + g_return_if_fail (config != NULL); + + config->refcount--; + if (config->refcount <= 0) + { + g_slist_foreach (config->nameservers, (GFunc) nameserver_id_free, NULL); + g_slist_free (config->nameservers); + g_slist_foreach (config->domains, (GFunc) domain_id_free, NULL); + g_slist_free (config->domains); + + memset (config, 0, sizeof (NMIP4Config)); + g_free (config); + } +} + +guint32 nm_ip4_config_get_address (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return config->ip4_address; +} + +void nm_ip4_config_set_address (NMIP4Config *config, guint32 addr) +{ + g_return_if_fail (config != NULL); + + config->ip4_address = addr; +} + +guint32 nm_ip4_config_get_gateway (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return config->ip4_gateway; +} + +void nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway) +{ + g_return_if_fail (config != NULL); + + config->ip4_gateway = gateway; +} + +guint32 nm_ip4_config_get_netmask (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return config->ip4_netmask; +} + +void nm_ip4_config_set_netmask (NMIP4Config *config, guint32 netmask) +{ + g_return_if_fail (config != NULL); + + config->ip4_netmask = netmask; +} + +guint32 nm_ip4_config_get_broadcast (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return config->ip4_broadcast; +} + +void nm_ip4_config_set_broadcast (NMIP4Config *config, guint32 broadcast) +{ + g_return_if_fail (config != NULL); + + config->ip4_broadcast = broadcast; +} + + +static NameserverID *nameserver_id_new (guint32 nameserver) +{ + NameserverID *ns = g_malloc0 (sizeof (NameserverID)); + + ns->ns_address = nameserver; + + return ns; +} + +static void nameserver_id_free (NameserverID *ns) +{ + g_free (ns); +} + +void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver) +{ + g_return_if_fail (config != NULL); + + config->nameservers = g_slist_append (config->nameservers, nameserver_id_new (nameserver)); +} + +guint32 nm_ip4_config_get_nameserver (NMIP4Config *config, guint index) +{ + NameserverID *ns; + + g_return_val_if_fail (config != NULL, 0); + g_return_val_if_fail (index < g_slist_length (config->nameservers), 0); + + if ((ns = g_slist_nth_data (config->nameservers, index))) + return ns->ns_address; + return 0; +} + +guint32 nm_ip4_config_get_nameserver_id (NMIP4Config *config, guint index) +{ + NameserverID *ns; + + g_return_val_if_fail (config != NULL, 0); + g_return_val_if_fail (index < g_slist_length (config->nameservers), 0); + + if ((ns = g_slist_nth_data (config->nameservers, index))) + return ns->ns_id; + return 0; +} + +void nm_ip4_config_set_nameserver_id (NMIP4Config *config, guint index, guint32 id) +{ + NameserverID *ns; + + g_return_if_fail (config != NULL); + g_return_if_fail (index < g_slist_length (config->nameservers)); + + if ((ns = g_slist_nth_data (config->nameservers, index))) + ns->ns_id = id; +} + +guint32 nm_ip4_config_get_num_nameservers (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return (g_slist_length (config->nameservers)); +} + + +static DomainID *domain_id_new (const char *domain) +{ + DomainID *did = g_malloc0 (sizeof (DomainID)); + + did->domain = g_strdup (domain); + + return did; +} + +static void domain_id_free (DomainID *did) +{ + if (!did) + return; + + g_free (did->domain); + g_free (did); +} + +void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) +{ + g_return_if_fail (config != NULL); + g_return_if_fail (domain != NULL); + + if (!strlen (domain)) + return; + + config->domains = g_slist_append (config->domains, domain_id_new (domain)); +} + +const char *nm_ip4_config_get_domain (NMIP4Config *config, guint index) +{ + DomainID *did; + + g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (index < g_slist_length (config->domains), NULL); + + if ((did = g_slist_nth_data (config->domains, index))) + return did->domain; + return NULL; +} + +guint32 nm_ip4_config_get_domain_id (NMIP4Config *config, guint index) +{ + DomainID *did; + + g_return_val_if_fail (config != NULL, 0); + g_return_val_if_fail (index < g_slist_length (config->domains), 0); + + if ((did = g_slist_nth_data (config->domains, index))) + return did->domain_id; + return 0; +} + +void nm_ip4_config_set_domain_id (NMIP4Config *config, guint index, guint32 id) +{ + DomainID *did; + + g_return_if_fail (config != NULL); + g_return_if_fail (index < g_slist_length (config->domains)); + + if ((did = g_slist_nth_data (config->domains, index))) + did->domain_id = id; +} + +guint32 nm_ip4_config_get_num_domains (NMIP4Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return (g_slist_length (config->domains)); +} diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h new file mode 100644 index 000000000..8cf29ac64 --- /dev/null +++ b/src/nm-ip4-config.h @@ -0,0 +1,59 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#ifndef NM_IP4_CONFIG_H +#define NM_IP4_CONFIG_H + +#include + +typedef struct NMIP4Config NMIP4Config; + + +NMIP4Config * nm_ip4_config_new (void); +NMIP4Config * nm_ip4_config_copy (NMIP4Config *config); +void nm_ip4_config_ref (NMIP4Config *config); +void nm_ip4_config_unref (NMIP4Config *config); + +guint32 nm_ip4_config_get_address (NMIP4Config *config); +void nm_ip4_config_set_address (NMIP4Config *config, guint32 addr); + +guint32 nm_ip4_config_get_gateway (NMIP4Config *config); +void nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway); + +guint32 nm_ip4_config_get_netmask (NMIP4Config *config); +void nm_ip4_config_set_netmask (NMIP4Config *config, guint32 netmask); + +guint32 nm_ip4_config_get_broadcast (NMIP4Config *config); +void nm_ip4_config_set_broadcast (NMIP4Config *config, guint32 broadcast); + +void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver); +guint32 nm_ip4_config_get_nameserver (NMIP4Config *config, guint index); +guint32 nm_ip4_config_get_nameserver_id (NMIP4Config *config, guint index); +void nm_ip4_config_set_nameserver_id (NMIP4Config *config, guint index, guint32 id); +guint32 nm_ip4_config_get_num_nameservers (NMIP4Config *config); + +void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain); +const char * nm_ip4_config_get_domain (NMIP4Config *config, guint index); +guint32 nm_ip4_config_get_domain_id (NMIP4Config *config, guint index); +void nm_ip4_config_set_domain_id (NMIP4Config *config, guint index, guint32 id); +guint32 nm_ip4_config_get_num_domains (NMIP4Config *config); + +#endif diff --git a/src/vpn-manager/.cvsignore b/src/vpn-manager/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/src/vpn-manager/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/src/vpn-manager/Makefile.am b/src/vpn-manager/Makefile.am new file mode 100644 index 000000000..926c953f7 --- /dev/null +++ b/src/vpn-manager/Makefile.am @@ -0,0 +1,26 @@ +INCLUDES = -I${top_srcdir}/utils -I${top_srcdir}/src -I${top_srcdir}/src/named-manager + +noinst_LTLIBRARIES = libvpn-manager.la + +libvpn_manager_la_SOURCES = nm-dbus-vpn.c \ + nm-dbus-vpn.h \ + nm-vpn-connection.c \ + nm-vpn-connection.h \ + nm-vpn-manager.c \ + nm-vpn-manager.h \ + nm-vpn-service.c \ + nm-vpn-service.h + +libvpn_manager_la_CPPFLAGS = $(DBUS_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + $(HAL_CFLAGS) \ + -g \ + -Wall \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" + + +libvpn_manager_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) diff --git a/src/vpn-manager/nm-dbus-vpn.c b/src/vpn-manager/nm-dbus-vpn.c new file mode 100644 index 000000000..333b153de --- /dev/null +++ b/src/vpn-manager/nm-dbus-vpn.c @@ -0,0 +1,594 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include "NetworkManagerMain.h" +#include "NetworkManagerDevice.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerUtils.h" +#include "nm-dbus-vpn.h" +#include "nm-vpn-manager.h" +#include "nm-vpn-connection.h" +#include "nm-utils.h" + + +/* + * nm_dbus_vpn_signal_vpn_connection_update + * + * Notifies the bus that a VPN connection has been added, deleted, or + * changed properties. + * + */ +void nm_dbus_vpn_signal_vpn_connection_update (DBusConnection *con, NMVPNConnection *vpn) +{ + DBusMessage *message; + const char *vpn_name; + + g_return_if_fail (con != NULL); + g_return_if_fail (vpn != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "VPNConnectionUpdate"))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + vpn_name = nm_vpn_connection_get_name (vpn); + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the VPNConnectionUpdate signal!"); + + dbus_message_unref (message); +} + + +/* + * nm_dbus_vpn_signal_vpn_connection_change + * + * Notifies the bus that the current VPN connection, if any, has changed. + * + */ +void nm_dbus_vpn_signal_vpn_connection_change (DBusConnection *con, NMVPNConnection *vpn) +{ + DBusMessage *message; + const char *vpn_name; + + g_return_if_fail (con != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "VPNConnectionChange"))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + if (vpn) + vpn_name = nm_vpn_connection_get_name (vpn); + else + vpn_name = ""; + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the VPNConnectionChange signal!"); + + dbus_message_unref (message); +} + + +/* + * nnm_dbus_vpn_signal_vpn_login_failed + * + * Pass the VPN Login Failure message from the daemon to the bus. + * + */ +void nm_dbus_vpn_signal_vpn_login_failed (DBusConnection *con, NMVPNConnection *vpn, const char *error_msg) +{ + DBusMessage *message; + const char *vpn_name; + + g_return_if_fail (con != NULL); + g_return_if_fail (vpn != NULL); + g_return_if_fail (error_msg != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "VPNLoginFailed"))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + vpn_name = nm_vpn_connection_get_name (vpn); + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the VPNLoginFailed signal!"); + + dbus_message_unref (message); +} + + +/* + * nnm_dbus_vpn_signal_vpn_login_banner + * + * Pass the VPN's login banner message to the bus if anyone wants to use it. + * + */ +void nm_dbus_vpn_signal_vpn_login_banner (DBusConnection *con, NMVPNConnection *vpn, const char *banner) +{ + DBusMessage *message; + const char *vpn_name; + + g_return_if_fail (con != NULL); + g_return_if_fail (vpn != NULL); + g_return_if_fail (banner != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "VPNLoginBanner"))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + vpn_name = nm_vpn_connection_get_name (vpn); + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the VPNLoginBanner signal!"); + + dbus_message_unref (message); +} + + +/* + * nm_dbus_vpn_get_vpn_data + * + * Get VPN specific data from NMI for a vpn connection + * + * NOTE: caller MUST free returned value using g_strfreev() + * + */ +static char ** nm_dbus_vpn_get_vpn_data (DBusConnection *connection, NMVPNConnection *vpn, int *num_items) +{ + DBusMessage *message; + DBusError error; + DBusMessage *reply; + char **data_items = NULL; + const char *vpn_name; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (vpn != NULL, NULL); + g_return_val_if_fail (num_items != NULL, NULL); + + *num_items = -1; + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getVPNConnectionVPNData"))) + { + nm_warning ("nm_dbus_vpn_get_vpn_data(): Couldn't allocate the dbus message"); + return (NULL); + } + + vpn_name = nm_vpn_connection_get_name (vpn); + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_INVALID); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + nm_warning ("nm_dbus_vpn_get_vpn_data(): %s raised %s", error.name, error.message); + else if (!reply) + nm_info ("nm_dbus_vpn_get_vpn_data(): reply was NULL."); + else + { + DBusMessageIter iter, array_iter; + GArray *buffer; + + dbus_message_iter_init (reply, &iter); + dbus_message_iter_recurse (&iter, &array_iter); + + buffer = g_array_new (TRUE, TRUE, sizeof (gchar *)); + + if (buffer == NULL) + return NULL; + + while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) + { + const char *value; + char *str; + + dbus_message_iter_get_basic (&array_iter, &value); + str = g_strdup (value); + + if (str == NULL) + { + g_array_free (buffer, TRUE); + return NULL; + } + + g_array_append_val (buffer, str); + + dbus_message_iter_next (&array_iter); + } + data_items = (gchar **)(buffer->data); + *num_items = buffer->len; + g_array_free (buffer, FALSE); + } + + if (reply) + dbus_message_unref (reply); + + return (data_items); +} + + +/* + * nm_dbus_vpn_add_one_connection + * + * Retrieve and add to our VPN Manager one VPN connection from NMI. + * + */ +NMVPNConnection *nm_dbus_vpn_add_one_connection (DBusConnection *con, const char *name, NMVPNManager *vpn_manager) +{ + DBusMessage *message; + DBusError error; + DBusMessage *reply; + const char *con_name = NULL; + const char *service_name = NULL; + const char *user_name = NULL; + DBusMessageIter iter; + NMVPNConnection *vpn = NULL; + + g_return_val_if_fail (con != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (vpn_manager != NULL, NULL); + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getVPNConnectionProperties"))) + { + nm_warning ("Couldn't allocate the dbus message"); + return NULL; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + + /* Send message and get properties back from NetworkManagerInfo */ + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (con, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + { + nm_warning ("nm_dbus_add_one_vpn_connections(): %s raised %s", error.name, error.message); + goto out; + } + if (!reply) + goto out; + + dbus_error_init (&error); + if (dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &con_name, DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, &user_name, DBUS_TYPE_INVALID)) + { + vpn = nm_vpn_manager_add_connection (vpn_manager, con_name, service_name, user_name); + } + dbus_message_unref (reply); + +out: + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + + return vpn; +} + + +/* + * nm_dbus_vpn_connections_update + * + * Update VPN connections from NetworkManagerInfo. + * + */ +gboolean nm_dbus_vpn_connections_update (NMData *data) +{ + DBusMessage *message; + DBusError error; + DBusMessage *reply; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data->dbus_connection != NULL, FALSE); + g_return_val_if_fail (data->vpn_manager != NULL, FALSE); + + /* Clear all existing connections in preparation for new ones */ + nm_vpn_manager_clear_connections (data->vpn_manager); + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getVPNConnections"))) + { + nm_warning ("nm_dbus_vpn_connections_update (): Couldn't allocate the dbus message"); + return FALSE; + } + + /* Send message and get essid back from NetworkManagerInfo */ + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (data->dbus_connection, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + nm_warning ("nm_dbus_vpn_connections_update(): %s raised %s", error.name, error.message); + else if (!reply) + nm_info ("nm_dbus_vpn_connections_update(): reply was NULL."); + else + { + DBusMessageIter iter, array_iter; + + dbus_message_iter_init (reply, &iter); + dbus_message_iter_recurse (&iter, &array_iter); + while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) + { + const char *value; + NMVPNConnection *vpn; + + dbus_message_iter_get_basic (&array_iter, &value); + if ((vpn = nm_dbus_vpn_add_one_connection (data->dbus_connection, value, data->vpn_manager))) + nm_dbus_vpn_signal_vpn_connection_update (data->dbus_connection, vpn); + dbus_message_iter_next(&array_iter); + } + } + + if (reply) + dbus_message_unref (reply); + + return FALSE; +} + + +/* + * nm_dbus_vpn_schedule_vpn_connections_update + * + * Schedule an update of VPN connections in the main thread + * + */ +void nm_dbus_vpn_schedule_vpn_connections_update (NMData *app_data) +{ + GSource *source = NULL; + + g_return_if_fail (app_data != NULL); + g_return_if_fail (app_data->main_context != NULL); + + source = g_idle_source_new (); + /* We want this idle source to run before any other idle source */ + g_source_set_priority (source, G_PRIORITY_HIGH_IDLE); + g_source_set_callback (source, (GSourceFunc) nm_dbus_vpn_connections_update, app_data, NULL); + g_source_attach (source, app_data->main_context); + g_source_unref (source); +} + + +/* + * nm_dbus_vpn_get_vpn_connections + * + * Returns a string array of VPN connection names. + * + */ +static DBusMessage *nm_dbus_vpn_get_vpn_connections (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter iter_array; + char **vpn_names = NULL; + int num_names; + int i; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + if (!data->data->vpn_manager) + { + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoVPNConnections", "There are no available VPN connections."); + goto out; + } + + vpn_names = nm_vpn_manager_get_connection_names (data->data->vpn_manager); + num_names = vpn_names ? g_strv_length (vpn_names) : 0; + if (num_names == 0) + { + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoVPNConnections", "There are no available VPN connections."); + goto out; + } + + if (!(reply = dbus_message_new_method_return (message))) + goto out; + + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); + + for (i = 0; i < num_names; i++) + { + dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &vpn_names[i]); + } + + dbus_message_iter_close_container (&iter, &iter_array); + +out: + if (vpn_names) + g_strfreev (vpn_names); + + return (reply); +} + + +/* + * nm_dbus_vpn_get_vpn_connection_properties + * + * Grab properties of a VPN connection + * + */ +static DBusMessage *nm_dbus_vpn_get_vpn_connection_properties (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + DBusError error; + const char *name; + const char *user_name; + gboolean good = FALSE; + NMVPNConnection *vpn_con; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + /* Check for no VPN Manager */ + if (!data->data->vpn_manager) + return nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoVPNConnections", "There are no available VPN connections."); + + if (!(reply = dbus_message_new_method_return (message))) + return NULL; + + dbus_error_init (&error); + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + { + if ((vpn_con = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) + { + const char *user_name = nm_vpn_connection_get_user_name (vpn_con); + + dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_INVALID); + good = TRUE; + } + } + + if (!good) + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "InvalidVPNConnections", "No VPN connection with that name was found."); + + return reply; +} + + +/* + * nm_dbus_vpn_get_active_vpn_connection + * + * Return the name of the currently active VPN connection. + * + */ +static DBusMessage *nm_dbus_vpn_get_active_vpn_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + const char *name; + NMVPNConnection *vpn = NULL; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + /* Check for no VPN Manager */ + if (!data->data->vpn_manager) + return nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoVPNConnections", "There are no available VPN connections."); + + if (!(vpn = nm_vpn_manager_get_active_vpn_connection (data->data->vpn_manager))) + return nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoActiveVPNConnection", "There is no active VPN connection."); + + if (!(reply = dbus_message_new_method_return (message))) + return NULL; + + name = nm_vpn_connection_get_name (vpn); + dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); + + return reply; +} + + +/* + * nm_dbus_vpn_activate_connection + * + * Activate a specific VPN connection. + * + */ +static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + DBusError error; + const char *name; + const char *password; + NMVPNConnection *vpn; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + dbus_error_init (&error); + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &password, DBUS_TYPE_INVALID)) + { + if ((vpn = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) + { + int item_count = -1; + char **items; + + if ((items = nm_dbus_vpn_get_vpn_data (connection, vpn, &item_count))) + { + char *joined_string = g_strjoinv (" / ", items); + NMVPNService *service = nm_vpn_connection_get_service (vpn);; + + nm_info ("Will activate VPN connection '%s', service '%s', user_name '%s', vpn_data '%s'.", + name, nm_vpn_service_get_name (service), nm_vpn_connection_get_user_name (vpn), joined_string); + nm_vpn_manager_activate_vpn_connection (data->data->vpn_manager, vpn, password, items, item_count); + + g_free (joined_string); + g_strfreev (items); + } + } + } + + return NULL; +} + + +/* + * nm_dbus_vpn_deactivate_connection + * + * Deactivate the active VPN connection, if any. + * + */ +static DBusMessage *nm_dbus_vpn_deactivate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + NMVPNConnection *vpn_con; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + nm_info ("Will deactivate the current VPN connection."); + nm_vpn_manager_deactivate_vpn_connection (data->data->vpn_manager); + + return NULL; +} + + +/* + * nm_dbus_vpn_methods_setup + * + * Register handlers for dbus methods on the + * org.freedesktop.NetworkManager.VPNConnections object. + * + */ +NMDbusMethodList *nm_dbus_vpn_methods_setup (void) +{ + NMDbusMethodList *list = nm_dbus_method_list_new (NULL); + + nm_dbus_method_list_add_method (list, "getVPNConnections", nm_dbus_vpn_get_vpn_connections); + nm_dbus_method_list_add_method (list, "getVPNConnectionProperties", nm_dbus_vpn_get_vpn_connection_properties); + nm_dbus_method_list_add_method (list, "getActiveVPNConnection", nm_dbus_vpn_get_active_vpn_connection); + nm_dbus_method_list_add_method (list, "activateVPNConnection", nm_dbus_vpn_activate_connection); + nm_dbus_method_list_add_method (list, "deactivateVPNConnection", nm_dbus_vpn_deactivate_connection); + + return (list); +} diff --git a/src/vpn-manager/nm-dbus-vpn.h b/src/vpn-manager/nm-dbus-vpn.h new file mode 100644 index 000000000..084c37473 --- /dev/null +++ b/src/vpn-manager/nm-dbus-vpn.h @@ -0,0 +1,40 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_DBUS_VPN_H +#define NM_DBUS_VPN_H + +#include "NetworkManagerDbusUtils.h" +#include "nm-vpn-manager.h" +#include "nm-vpn-connection.h" + + +NMVPNConnection * nm_dbus_vpn_add_one_connection (DBusConnection *con, const char *name, NMVPNManager *vpn_manager); +void nm_dbus_vpn_schedule_vpn_connections_update (NMData *app_data); + +void nm_dbus_vpn_signal_vpn_connection_update (DBusConnection *con, NMVPNConnection *vpn); +void nm_dbus_vpn_signal_vpn_connection_change (DBusConnection *con, NMVPNConnection *vpn); +void nm_dbus_vpn_signal_vpn_login_failed (DBusConnection *con, NMVPNConnection *vpn, const char *error_msg); +void nm_dbus_vpn_signal_vpn_login_banner (DBusConnection *con, NMVPNConnection *vpn, const char *banner); + +NMDbusMethodList * nm_dbus_vpn_methods_setup (void); + +#endif diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c new file mode 100644 index 000000000..223fd3c3c --- /dev/null +++ b/src/vpn-manager/nm-vpn-connection.c @@ -0,0 +1,101 @@ +/* nm-vpn-connection.c - handle a single VPN connections within NetworkManager's framework + * + * Copyright (C) 2005 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" +#include +#include +#include "nm-vpn-connection.h" + + +struct NMVPNConnection +{ + int refcount; + char *name; + char *user_name; + NMVPNService *service; +}; + + +NMVPNConnection *nm_vpn_connection_new (const char *name, const char *user_name, NMVPNService *service) +{ + NMVPNConnection *connection; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (user_name != NULL, NULL); + g_return_val_if_fail (service != NULL, NULL); + + + connection = g_malloc0 (sizeof (NMVPNConnection)); + connection->refcount = 1; + + connection->name = g_strdup (name); + connection->user_name = g_strdup (user_name); + + nm_vpn_service_ref (service); + connection->service = service; + + return connection; +} + + +void nm_vpn_connection_ref (NMVPNConnection *connection) +{ + g_return_if_fail (connection != NULL); + + connection->refcount++; +} + +void nm_vpn_connection_unref (NMVPNConnection *connection) +{ + g_return_if_fail (connection != NULL); + + connection->refcount--; + if (connection->refcount <= 0) + { + g_free (connection->name); + g_free (connection->user_name); + nm_vpn_service_unref (connection->service); + + memset (connection, 0, sizeof (NMVPNConnection)); + g_free (connection); + } +} + +const char *nm_vpn_connection_get_name (NMVPNConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->name; +} + +const char *nm_vpn_connection_get_user_name (NMVPNConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->user_name; +} + +NMVPNService *nm_vpn_connection_get_service (NMVPNConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->service; +} + diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h new file mode 100644 index 000000000..7109c1559 --- /dev/null +++ b/src/vpn-manager/nm-vpn-connection.h @@ -0,0 +1,36 @@ +/* nm-vpn-connection.h - handle a single VPN connection within NetworkManager's framework + * + * Copyright (C) 2005 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef NM_VPN_CONNECTION_H +#define NM_VPN_CONNECTION_H + +#include "nm-vpn-service.h" + +typedef struct NMVPNConnection NMVPNConnection; + + +NMVPNConnection *nm_vpn_connection_new (const char *name, const char *user_name, NMVPNService *service); +void nm_vpn_connection_ref (NMVPNConnection *connection); +void nm_vpn_connection_unref (NMVPNConnection *connection); + +const char * nm_vpn_connection_get_name (NMVPNConnection *connection); +const char * nm_vpn_connection_get_user_name (NMVPNConnection *connection); +NMVPNService * nm_vpn_connection_get_service (NMVPNConnection *connection); + +#endif /* NM_VPN_MANAGER_H */ diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c new file mode 100644 index 000000000..71a5a1fe7 --- /dev/null +++ b/src/vpn-manager/nm-vpn-manager.c @@ -0,0 +1,837 @@ +/* nm-vpn-manager.c - handle VPN connections within NetworkManager's framework + * + * Copyright (C) 2005 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "nm-vpn-manager.h" +#include "NetworkManager.h" +#include "NetworkManagerMain.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerSystem.h" +#include "nm-vpn-connection.h" +#include "nm-vpn-service.h" +#include "nm-dbus-vpn.h" +#include "nm-utils.h" + +#define VPN_SERVICE_FILE_PATH SYSCONFDIR"/NetworkManager/VPN" + +struct NMVPNManager +{ + NMData * app_data; + GSList * services; + GSList * connections; + NMVPNConnection * active; + char * active_device; + NMIP4Config * active_config; +}; + +static GSList * nm_vpn_manager_load_services (void); +static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NMVPNConnection *con); + +/* + * nm_vpn_manager_new + * + * Create a new VPN manager instance. + * + */ +NMVPNManager *nm_vpn_manager_new (NMData *app_data) +{ + NMVPNManager *manager; + + g_return_val_if_fail (app_data != NULL, NULL); + + manager = g_malloc0 (sizeof (NMVPNManager)); + manager->services = nm_vpn_manager_load_services (); + manager->app_data = app_data; + + return manager; +} + + +/* + * nm_vpn_manager_dispose + * + * Release the VPN manager and all its data. + * + */ +void nm_vpn_manager_dispose (NMVPNManager *manager) +{ + g_return_if_fail (manager != NULL); + + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + if (manager->active_device) + g_free (manager->active_device); + + if (manager->active_config) + { + nm_system_remove_ip4_config_nameservers (manager->app_data->named, manager->active_config); + nm_system_remove_ip4_config_search_domains (manager->app_data->named, manager->active_config); + nm_ip4_config_unref (manager->active_config); + } + + g_slist_foreach (manager->connections, (GFunc) nm_vpn_connection_unref, NULL); + g_slist_free (manager->connections); + + g_slist_foreach (manager->services, (GFunc) nm_vpn_service_unref, NULL); + g_slist_free (manager->services); + + memset (manager, 0, sizeof (NMVPNManager)); + g_free (manager); +} + + +/* + * nm_vpn_manager_clear_connections + * + * Dispose of all the VPN connections the manager knows about. + * + */ +void nm_vpn_manager_clear_connections (NMVPNManager *manager) +{ + g_return_if_fail (manager != NULL); + + g_slist_foreach (manager->connections, (GFunc)nm_vpn_connection_unref, NULL); +} + + +/* + * find_vpn_service + * + * Return the VPN Service for a given vpn service name. + * + */ +static NMVPNService *find_service_by_name (NMVPNManager *manager, const char *service_name) +{ + NMVPNService *service = NULL; + GSList *elt; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + + for (elt = manager->services; elt; elt = g_slist_next (elt)) + { + if ((service = (NMVPNService *)(elt->data))) + { + const char *search_name = nm_vpn_service_get_name (service); + if (search_name && (strcmp (service_name, search_name) == 0)) + break; + } + service = NULL; + } + + return service; +} + + +/* + * nm_vpn_manager_find_connection_by_name + * + * Return the NMVPNConnection object associated with a particular name. + * + */ +NMVPNConnection *nm_vpn_manager_find_connection_by_name (NMVPNManager *manager, const char *con_name) +{ + NMVPNConnection *con = NULL; + GSList *elt; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (con_name != NULL, NULL); + + for (elt = manager->connections; elt; elt = g_slist_next (elt)) + { + if ((con = (NMVPNConnection *)(elt->data))) + { + const char *search_name = nm_vpn_connection_get_name (con); + if (search_name && (strcmp (con_name, search_name) == 0)) + break; + } + con = NULL; + } + + return con; +} + + +/* + * nm_vpn_manager_set_active_vpn_connection + * + * Sets the active connection and adds a dbus signal filter for that + * connection's service name. + * + */ +static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NMVPNConnection *con) +{ + char *match_string = NULL; + const char *service_name = NULL; + NMVPNConnection *active; + NMVPNService *service; + + g_return_if_fail (manager != NULL); + + if ((active = nm_vpn_manager_get_active_vpn_connection (manager))) + { + service = nm_vpn_connection_get_service (active); + if (service && (service_name = nm_vpn_service_get_name (service))) + { + /* Remove any previous watch on this VPN connection's service name */ + match_string = g_strdup_printf ("type='signal'," + "interface='%s'," + "sender='%s'", service_name, service_name); + dbus_bus_remove_match (manager->app_data->dbus_connection, match_string, NULL); + g_free (match_string); + } + nm_vpn_connection_unref (active); + } + manager->active = NULL; + + if (manager->active_config) + { + nm_system_remove_ip4_config_nameservers (manager->app_data->named, manager->active_config); + nm_system_remove_ip4_config_search_domains (manager->app_data->named, manager->active_config); + nm_ip4_config_unref (manager->active_config); + manager->active_config = NULL; + } + + if (manager->active_device) + { +nm_info ("Clearing active VPN device '%s'.", manager->active_device); + nm_system_device_set_up_down_with_iface (NULL, manager->active_device, FALSE); + nm_system_device_flush_routes_with_iface (manager->active_device); + nm_system_device_flush_addresses_with_iface (manager->active_device); + g_free (manager->active_device); + manager->active_device = NULL; + } + + nm_dbus_vpn_signal_vpn_connection_change (manager->app_data->dbus_connection, con); + + /* If passed NULL (clear active connection) there's nothing more to do */ + if (!con) + return; + + service = nm_vpn_connection_get_service (con); + if (!service || !(service_name = nm_vpn_service_get_name (service))) + { + nm_warning ("VPN connection could not be set active because it didn't have a VPN service."); + return; + } + + nm_vpn_connection_ref (con); + manager->active = con; + + /* Add a dbus filter for this connection's service name so its signals + * get delivered to us. + */ + match_string = g_strdup_printf ("type='signal'," + "interface='%s'," + "sender='%s'", service_name, service_name); + dbus_bus_add_match (manager->app_data->dbus_connection, match_string, NULL); + g_free (match_string); +} + + +/* + * nm_vpn_manager_add_connection + * + * Add a new VPN connection if none already exits, otherwise update the existing one. + * + */ +NMVPNConnection *nm_vpn_manager_add_connection (NMVPNManager *manager, const char *name, const char *service_name, const char *user_name) +{ + NMVPNConnection *connection = NULL; + NMVPNService *service; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (user_name != NULL, NULL); + + /* Verify that the service name we are adding is in our allowed list */ + service = find_service_by_name (manager, service_name); + if (service && (connection = nm_vpn_connection_new (name, user_name, service))) + { + gboolean found = FALSE; + GSList *elt; + + /* Remove the existing connection if found */ + for (elt = manager->connections; elt; elt = g_slist_next (elt)) + { + NMVPNConnection *con = (NMVPNConnection *)(elt->data); + + if (con && nm_vpn_connection_get_name (con) && (strcmp (nm_vpn_connection_get_name (con), name) == 0)) + { + manager->connections = g_slist_remove_link (manager->connections, elt); + nm_vpn_connection_unref (con); + g_slist_free (elt); + } + } + + /* Add in the updated connection */ + manager->connections = g_slist_append (manager->connections, connection); + } + + return connection; +} + + +/* + * Prints config returned from vpnc-helper + */ +static void print_vpn_config (guint32 ip4_vpn_gateway, + const char *tundev, + guint32 ip4_internal_address, + gint32 ip4_internal_netmask, + guint32 *ip4_internal_dns, + guint32 ip4_internal_dns_len, + guint32 *ip4_internal_nbns, + guint32 ip4_internal_nbns_len, + const char *dns_domain, + const char *login_banner) +{ + struct in_addr temp_addr; + guint32 i; + + temp_addr.s_addr = ip4_vpn_gateway; + nm_info ("VPN Gateway: %s", inet_ntoa (temp_addr)); + nm_info ("Tunnel Device: %s", tundev); + temp_addr.s_addr = ip4_internal_address; + nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); + temp_addr.s_addr = ip4_internal_netmask; + nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); + + for (i = 0; i < ip4_internal_dns_len; i++) + { + if (ip4_internal_dns[i] != 0) + { + temp_addr.s_addr = ip4_internal_dns[i]; + nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); + } + } + + for (i = 0; i < ip4_internal_nbns_len; i++) + { + if (ip4_internal_nbns[i] != 0) + { + temp_addr.s_addr = ip4_internal_nbns[i]; + nm_info ("Internal IP4 NBNS: %s", inet_ntoa (temp_addr)); + } + } + + nm_info ("DNS Domain: '%s'", dns_domain); + nm_info ("Login Banner:"); + nm_info ("-----------------------------------------"); + nm_info ("%s", login_banner); + nm_info ("-----------------------------------------"); +} + +/* + * nm_vpn_manager_handle_ip4_config_signal + * + * Configure a device with IPv4 config info in response the the VPN daemon. + * + */ +void nm_vpn_manager_handle_ip4_config_signal (NMVPNManager *manager, DBusMessage *message, NMVPNService *service, NMVPNConnection *con) +{ + guint32 ip4_vpn_gateway; + char * tundev; + guint32 ip4_internal_address; + guint32 ip4_internal_netmask; + guint32 * ip4_internal_dns; + guint32 ip4_internal_dns_len; + guint32 * ip4_internal_nbns; + guint32 ip4_internal_nbns_len; + char * dns_domain; + char * login_banner; + + g_return_if_fail (manager != NULL); + g_return_if_fail (message != NULL); + g_return_if_fail (service != NULL); + g_return_if_fail (con != NULL); + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ip4_vpn_gateway, + DBUS_TYPE_STRING, &tundev, + DBUS_TYPE_UINT32, &ip4_internal_address, + DBUS_TYPE_UINT32, &ip4_internal_netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_dns, &ip4_internal_dns_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_nbns, &ip4_internal_nbns_len, + DBUS_TYPE_STRING, &dns_domain, + DBUS_TYPE_STRING, &login_banner, DBUS_TYPE_INVALID)) + { + NMIP4Config * config; + NMDevice * vpn_dev; + guint32 i; + guint32 broadcast; + +#if 0 + print_vpn_config (ip4_vpn_gateway, tundev, ip4_internal_address, ip4_internal_netmask, + ip4_internal_dns, ip4_internal_dns_len, ip4_internal_nbns, ip4_internal_nbns_len, + dns_domain, login_banner); +#endif + + config = nm_ip4_config_new (); + + nm_ip4_config_set_address (config, ip4_internal_address); + + if (ip4_internal_netmask) + nm_ip4_config_set_netmask (config, ip4_internal_netmask); + else + nm_ip4_config_set_netmask (config, 0x00FF); /* Class C */ + + nm_ip4_config_set_gateway (config, ip4_vpn_gateway); + + if (strlen (dns_domain)) + nm_ip4_config_add_domain (config, dns_domain); + + for (i = 0; i < ip4_internal_dns_len; i++) + { + if (ip4_internal_dns[i] != 0) + nm_ip4_config_add_nameserver (config, ip4_internal_dns[i]); + } + + manager->active_device = g_strdup (tundev); + manager->active_config = config; + nm_system_vpn_device_set_from_ip4_config (manager->app_data->named, manager->app_data->active_device, + manager->active_device, manager->active_config); + if (login_banner && strlen (login_banner)) + nm_dbus_vpn_signal_vpn_login_banner (manager->app_data->dbus_connection, con, login_banner); + } +} + + +/* + * nm_vpn_manager_get_connection_names + * + * Return an array of strings of all the VPN Connection names + * we know about. + * + */ +char **nm_vpn_manager_get_connection_names (NMVPNManager *manager) +{ + char **names = NULL; + GSList *elt; + int i; + + g_return_val_if_fail (manager != NULL, NULL); + + names = g_malloc0 ((g_slist_length (manager->connections) + 1) * sizeof (char *)); + for (elt = manager->connections, i = 0; elt; elt = g_slist_next (elt), i++) + { + NMVPNConnection *vpn_con = (NMVPNConnection *)(elt->data); + if (vpn_con) + names[i] = g_strdup (nm_vpn_connection_get_name (vpn_con)); + } + + return names; +} + + +/* + * nm_vpn_manager_get_active_vpn_connection + * + * Return the active VPN connection, if any. + * + */ +NMVPNConnection *nm_vpn_manager_get_active_vpn_connection (NMVPNManager *manager) +{ + g_return_val_if_fail (manager != NULL, NULL); + + return manager->active; +} + + +/* + * construct_op_from_service_name + * + * Construct an object path from a dbus service name by replacing + * all "." in the service with "/" and prepending a "/" to the + * object path. + * + */ +static char *construct_op_from_service_name (const char *service_name) +{ + char **split = NULL; + char *temp1; + char *temp2; + + g_return_val_if_fail (service_name != NULL, NULL); + + if (!(split = g_strsplit (service_name, ".", 0))) + return NULL; + + temp1 = g_strjoinv ("/", split); + g_strfreev (split); + temp2 = g_strdup_printf ("/%s", temp1); + g_free (temp1); + + if (!temp2 || !strlen (temp2)) + { + g_free (temp2); + temp2 = NULL; + } + + return temp2; +} + + +/* + * nm_vpn_manager_process_signal + * + * Possibly process a signal from the bus, if it comes from the currently + * active VPN daemon, if any. Return TRUE if processed, FALSE if not. + * + */ +gboolean nm_vpn_manager_process_signal (NMVPNManager *manager, DBusMessage *message) +{ + const char *object_path; + const char *temp_op; + NMVPNConnection *active; + NMVPNService *service; + const char *service_name; + + g_return_val_if_fail (manager != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + if (!(object_path = dbus_message_get_path (message))) + return FALSE; + + if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) + return FALSE; + + service = nm_vpn_connection_get_service (active); + if (!service || !(service_name = nm_vpn_service_get_name (service))) + return FALSE; + + temp_op = construct_op_from_service_name (service_name); + if (!temp_op || (strcmp (object_path, temp_op) != 0)) + return FALSE; + + if (dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED)) + { + char *error_msg; + char *blank_msg = ""; + + if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) + error_msg = blank_msg; + nm_warning ("VPN Login failed for service '%s' with message '%s'.", service_name, error_msg); + nm_dbus_vpn_signal_vpn_login_failed (manager->app_data->dbus_connection, active, error_msg); + } + else if (dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_STATE_CHANGE)) + { + NMVPNState old_state; + NMVPNState new_state; + + if (dbus_message_get_args (message, NULL, DBUS_TYPE_UINT32, &old_state, DBUS_TYPE_UINT32, &new_state, DBUS_TYPE_INVALID)) + { + nm_info ("VPN service '%s' signaled new state %d, old state %d.", service_name, new_state, old_state); + nm_vpn_service_set_state (service, new_state); + + /* If the VPN daemon state is now stopped and it was starting, clear the active connection */ + if (((new_state == NM_VPN_STATE_STOPPED) || (new_state == NM_VPN_STATE_SHUTDOWN) || (new_state == NM_VPN_STATE_STOPPING)) + && ((old_state == NM_VPN_STATE_STARTED) || (old_state == NM_VPN_STATE_STARTING))) + { + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + } + } + } + else if (dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_IP4_CONFIG)) + nm_vpn_manager_handle_ip4_config_signal (manager, message, service, active); + + return TRUE; +} + + +/* + * nm_vpn_manager_process_name_owner_changed + * + * Respond to "service created"/"service deleted" signals from dbus for our active VPN daemon. + * + */ +gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const char *changed_service_name, const char *old_owner, const char *new_owner) +{ + NMVPNService *service; + NMVPNConnection *active; + gboolean old_owner_good = (old_owner && strlen (old_owner)); + gboolean new_owner_good = (new_owner && strlen (new_owner)); + + g_return_val_if_fail (manager != NULL, FALSE); + g_return_val_if_fail (changed_service_name != NULL, FALSE); + + if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) + return FALSE; + nm_vpn_connection_ref (active); + + if (!(service = nm_vpn_connection_get_service (active))) + { + nm_vpn_connection_unref (active); + return FALSE; + } + + /* Can't handle the signal if its not from our active VPN service */ + if (strcmp (nm_vpn_service_get_name (service), changed_service_name) != 0) + { + nm_vpn_connection_unref (active); + return FALSE; + } + + if (!old_owner_good && new_owner_good) + { + /* VPN service got created. */ + } + else if (old_owner_good && !new_owner_good) + { + /* VPN service went away. */ + nm_vpn_service_set_state (service, NM_VPN_STATE_SHUTDOWN); + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + nm_dbus_vpn_signal_vpn_connection_change (manager->app_data->dbus_connection, active); + } + + nm_vpn_connection_unref (active); + return TRUE; +} + + +/* + * nm_vpn_manager_activate_vpn_connection + * + * Signal the VPN service daemon to activate a particular VPN connection, + * launching that daemon if necessary. + * + */ +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, const char *password, char **data_items, int count) +{ + DBusMessage *message; + DBusMessage *reply; + char *op; + NMVPNService *service; + const char *service_name; + const char *name; + const char *user_name; + DBusMessageIter iter, array_iter; + int i, len; + DBusError error; + + g_return_if_fail (manager != NULL); + g_return_if_fail (manager->app_data != NULL); + g_return_if_fail (manager->app_data->dbus_connection != NULL); + g_return_if_fail (vpn != NULL); + g_return_if_fail (password != NULL); + g_return_if_fail (data_items != NULL); + + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + + /* Construct a new method call with the correct service and object path */ + if (!(service = nm_vpn_connection_get_service (vpn)) || !(service_name = nm_vpn_service_get_name (service))) + return; + + nm_vpn_manager_set_active_vpn_connection (manager, vpn); + + /* Start the daemon if its not already running */ + if (!dbus_bus_name_has_owner (manager->app_data->dbus_connection, service_name, NULL)) + { + if (!nm_vpn_service_exec_daemon (service)) + { + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + return; + } + } + + /* Send the activate request to the daemon */ + op = construct_op_from_service_name (service_name); + message = dbus_message_new_method_call (service_name, op, service_name, "startConnection"); + g_free (op); + if (!message) + { + nm_warning ("Couldn't allocate dbus message."); + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + return; + } + + name = nm_vpn_connection_get_name (vpn); + user_name = nm_vpn_connection_get_user_name (vpn); + + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_STRING, &password, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, count, + DBUS_TYPE_INVALID); + + /* Send the message to the daemon again, now that its running. */ + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (manager->app_data->dbus_connection, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + { + nm_warning ("Could not activate the VPN service. dbus says: '%s' '%s'.", error.name, error.message); + dbus_error_free (&error); + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + return; + } + + if (reply) + dbus_message_unref (reply); +} + + +/* + * nm_vpn_manager_deactivate_vpn_connection + * + * Signal the VPN service daemon to deactivate a particular VPN connection. + * + */ +void nm_vpn_manager_deactivate_vpn_connection (NMVPNManager *manager) +{ + DBusMessage *message; + char *op; + NMVPNService *service; + const char *service_name; + NMVPNConnection *active; + NMIP4Config *config; + + g_return_if_fail (manager != NULL); + + if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) + return; + nm_vpn_connection_ref (active); + + /* Construct a new method call with the correct service and object path */ + service = nm_vpn_connection_get_service (active); + service_name = nm_vpn_service_get_name (service); + op = construct_op_from_service_name (service_name); + message = dbus_message_new_method_call (service_name, op, service_name, "stopConnection"); + g_free (op); + if (!message) + { + nm_warning ("Couldn't allocate dbus message."); + goto out; + } + + /* Call the specific VPN service, let dbus activate it if needed */ + dbus_connection_send (manager->app_data->dbus_connection, message, NULL); + dbus_message_unref (message); + +out: + nm_vpn_manager_set_active_vpn_connection (manager, NULL); + nm_dbus_vpn_signal_vpn_connection_change (manager->app_data->dbus_connection, NULL); + nm_vpn_connection_unref (active); + + if (manager->app_data->active_device) + nm_system_device_set_from_ip4_config (manager->app_data->active_device); +} + + +/*********************************************************************/ + +static GSList *nm_vpn_manager_load_services (void) +{ + GSList *list = NULL; + GDir *vpn_dir; + + /* Load allowed service names */ + if ((vpn_dir = g_dir_open (VPN_SERVICE_FILE_PATH, 0, NULL))) + { + const char *file_name; + + while ((file_name = g_dir_read_name (vpn_dir))) + { + char *file_path = g_strdup_printf (VPN_SERVICE_FILE_PATH"/%s", file_name); + char *contents; + + if (g_file_get_contents (file_path, &contents, NULL, NULL) && (contents != NULL)) + { + char **split_contents = g_strsplit (contents, "\n", 0); + + if (split_contents) + { + int i, len; + NMVPNService *service = nm_vpn_service_new (); + gboolean have_name = FALSE; + gboolean have_program = FALSE; + + len = g_strv_length (split_contents); + for (i = 0; i < len; i++) + { + char *line = split_contents[i]; + + #define SERVICE_TAG "service=" + #define PROGRAM_TAG "program=" + + if (!line || !strlen (line)) continue; + + /* Comment lines begin with # */ + if (line[0] == '#') continue; + + if (strlen (line) > 8) + { + if ((strncmp (line, SERVICE_TAG, strlen (SERVICE_TAG)) == 0) && !have_name) + { + char *service_name = g_strdup (line+strlen (SERVICE_TAG)); + + /* Deny the load if the service name is NetworkManager or NetworkManagerInfo. */ + if (strcmp (service_name, NM_DBUS_SERVICE) && strcmp (service_name, NM_DBUS_SERVICE)) + nm_vpn_service_set_name (service, (const char *)service_name); + else + nm_warning ("VPN service name matched NetworkManager or NetworkManagerInfo service names, " + "which is not allowed and might be malicious."); + g_free (service_name); + have_name = TRUE; + } + else if ((strncmp (line, PROGRAM_TAG, strlen (PROGRAM_TAG)) == 0) && !have_program) + { + gboolean program_ok = FALSE; + if ((strlen (line) >= strlen (PROGRAM_TAG) + 1)) + { + if ((*(line+strlen (PROGRAM_TAG)) == '/') && (*(line+strlen (line)-1) != '/')) + { + nm_vpn_service_set_program (service, (const char *)(line+strlen (PROGRAM_TAG))); + program_ok = TRUE; + } + } + if (!program_ok) + nm_warning ("WARNING: VPN program '%s' invalid in file '%s'", line, file_path); + have_program = TRUE; + } + } + } + g_strfreev (split_contents); + + if (nm_vpn_service_get_name (service) && nm_vpn_service_get_program (service)) + { + nm_info ("Adding VPN service '%s' with program '%s'", nm_vpn_service_get_name (service), + nm_vpn_service_get_program (service)); + list = g_slist_append (list, service); + } + else + nm_vpn_service_unref (service); + } + g_free (contents); + } + g_free (file_path); + } + + g_dir_close (vpn_dir); + } + + return list; +} + diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h new file mode 100644 index 000000000..37e887e9f --- /dev/null +++ b/src/vpn-manager/nm-vpn-manager.h @@ -0,0 +1,44 @@ +/* nm-vpn-manager.h - handle VPN connections within NetworkManager's framework + * + * Copyright (C) 2005 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef NM_VPN_MANAGER_H +#define NM_VPN_MANAGER_H + +#include +#include "NetworkManagerMain.h" +#include "nm-vpn-connection.h" + + +NMVPNManager * nm_vpn_manager_new (NMData *app_data); +void nm_vpn_manager_clear_connections (NMVPNManager *manager); +NMVPNConnection * nm_vpn_manager_add_connection (NMVPNManager *manager, const char *name, const char *service_name, const char *user_name); +char ** nm_vpn_manager_get_connection_names (NMVPNManager *manager); +void nm_vpn_manager_dispose (NMVPNManager *manager); + +NMVPNConnection * nm_vpn_manager_get_active_vpn_connection (NMVPNManager *manager); + +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, const char *password, char **data_items, int count); +void nm_vpn_manager_deactivate_vpn_connection (NMVPNManager *manager); + +NMVPNConnection * nm_vpn_manager_find_connection_by_name (NMVPNManager *manager, const char *con_name); + +gboolean nm_vpn_manager_process_signal (NMVPNManager *manager, DBusMessage *signal); +gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const char *service, const char *old_owner, const char *new_owner); + +#endif /* NM_VPN_MANAGER_H */ diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c new file mode 100644 index 000000000..5200fbfee --- /dev/null +++ b/src/vpn-manager/nm-vpn-service.c @@ -0,0 +1,154 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include "nm-dbus-vpn.h" +#include "nm-vpn-service.h" +#include "nm-utils.h" + + +struct NMVPNService +{ + int refcount; + char *name; + char *program; + NMVPNState state; +}; + + +NMVPNService *nm_vpn_service_new (void) +{ + NMVPNService *service = g_malloc0 (sizeof (NMVPNService)); + + service->refcount = 1; + service->state = NM_VPN_STATE_SHUTDOWN; + + return service; +} + +void nm_vpn_service_ref (NMVPNService *service) +{ + g_return_if_fail (service != NULL); + + service->refcount++; +} + + +void nm_vpn_service_unref (NMVPNService *service) +{ + g_return_if_fail (service != NULL); + + service->refcount--; + if (service->refcount <= 0) + { + g_free (service->name); + g_free (service->program); + memset (service, 0, sizeof (NMVPNService)); + g_free (service); + } +} + + +const char *nm_vpn_service_get_name (NMVPNService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->name; +} + + +void nm_vpn_service_set_name (NMVPNService *service, const char *name) +{ + g_return_if_fail (service != NULL); + + if (service->name) + g_free (service->name); + service->name = g_strdup (name); +} + + +const char *nm_vpn_service_get_program (NMVPNService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->program; +} + + +void nm_vpn_service_set_program (NMVPNService *service, const char *program) +{ + g_return_if_fail (service != NULL); + + if (service->program) + g_free (service->program); + service->program = g_strdup (program); +} + + +NMVPNState nm_vpn_service_get_state (NMVPNService *service) +{ + g_return_val_if_fail (service != NULL, NM_VPN_STATE_ERROR); + + return service->state; +} + + +void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state) +{ + g_return_if_fail (service != NULL); + + service->state = state; +} + + +gboolean nm_vpn_service_exec_daemon (NMVPNService *service) +{ + GPtrArray *vpn_argv; + GError *error = NULL; + GPid pid; + + g_return_val_if_fail (service != NULL, FALSE); + + if (!nm_vpn_service_get_program (service)) + return FALSE; + + vpn_argv = g_ptr_array_new (); + g_ptr_array_add (vpn_argv, (char *) nm_vpn_service_get_program (service)); + g_ptr_array_add (vpn_argv, NULL); + + if (!g_spawn_async (NULL, (char **) vpn_argv->pdata, NULL, 0, NULL, NULL, &pid, &error)) + { + g_ptr_array_free (vpn_argv, TRUE); + nm_warning ("Could not activate the VPN service '%s'. error: '%s'.", nm_vpn_service_get_name (service), error->message); + g_error_free (error); + return FALSE; + } + g_ptr_array_free (vpn_argv, TRUE); + nm_info ("Activated the VPN service '%s' with PID %d.", nm_vpn_service_get_name (service), pid); + + /* Wait a bit for the daemon to start up */ + /* FIXME: don't sleep, keep retrying dbus message or something */ + sleep (1); + + return TRUE; +} + diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h new file mode 100644 index 000000000..0b221c5f0 --- /dev/null +++ b/src/vpn-manager/nm-vpn-service.h @@ -0,0 +1,48 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_VPN_SERVICE_H +#define NM_VPN_SERVICE_H + + +#include +#include "NetworkManager.h" + + +typedef struct NMVPNService NMVPNService; + +NMVPNService * nm_vpn_service_new (void); + +void nm_vpn_service_ref (NMVPNService *service); +void nm_vpn_service_unref (NMVPNService *service); + +const char * nm_vpn_service_get_name (NMVPNService *service); +void nm_vpn_service_set_name (NMVPNService *service, const char *name); + +const char * nm_vpn_service_get_program (NMVPNService *service); +void nm_vpn_service_set_program (NMVPNService *service, const char *program); + +NMVPNState nm_vpn_service_get_state (NMVPNService *service); +void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state); + +gboolean nm_vpn_service_exec_daemon (NMVPNService *service); + +#endif diff --git a/vpn-daemons/.cvsignore b/vpn-daemons/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/vpn-daemons/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/vpn-daemons/Makefile.am b/vpn-daemons/Makefile.am new file mode 100644 index 000000000..ba0a3eb59 --- /dev/null +++ b/vpn-daemons/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = vpnc + diff --git a/vpn-daemons/vpnc/.cvsignore b/vpn-daemons/vpnc/.cvsignore new file mode 100644 index 000000000..d52debf93 --- /dev/null +++ b/vpn-daemons/vpnc/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +nm-vpnc-service +nm-vpnc-service-vpnc-helper diff --git a/vpn-daemons/vpnc/Makefile.am b/vpn-daemons/vpnc/Makefile.am new file mode 100644 index 000000000..083fd09af --- /dev/null +++ b/vpn-daemons/vpnc/Makefile.am @@ -0,0 +1,45 @@ +INCLUDES = -I${top_srcdir} -I${top_srcdir}/utils + +AM_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + -Wall \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DPREFIX=\""$(prefix)"\" \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DVERSION="\"$(VERSION)\"" \ + -DLIBDIR=\""$(libdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DLOCALSTATEDIR=\""$(localstatedir)"\" \ + -DDATADIR=\"$(datadir)\" + +bin_PROGRAMS = nm-vpnc-service nm-vpnc-service-vpnc-helper + +nm_vpnc_service_SOURCES = \ + nm-vpnc-service.c + +nm_vpnc_service_LDADD = \ + $(DBUS_LIBS) \ + $(GTHREAD_LIBS) \ + $(top_builddir)/utils/libnmutils.la + + +nm_vpnc_service_vpnc_helper_SOURCES = \ + nm-vpnc-service-vpnc-helper.c + +nm_vpnc_service_vpnc_helper_LDADD = \ + $(DBUS_LIBS) \ + $(GTHREAD_LIBS) \ + $(top_builddir)/utils/libnmutils.la + + +dbusservicedir = $(DBUS_SYS_DIR) +dbusservice_DATA = nm-vpnc-service.conf + +nmvpnservicedir = $(sysconfdir)/NetworkManager/VPN +nmvpnservice_DATA = nm-vpnc-service.name + +EXTRA_DIST = $(dbusservice_DATA) $(nmvpnservice_DATA) + diff --git a/vpn-daemons/vpnc/nm-vpnc-service-vpnc-helper.c b/vpn-daemons/vpnc/nm-vpnc-service-vpnc-helper.c new file mode 100644 index 000000000..134713db6 --- /dev/null +++ b/vpn-daemons/vpnc/nm-vpnc-service-vpnc-helper.c @@ -0,0 +1,319 @@ +/* nm-vpnc-service - vpnc integration with NetworkManager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "NetworkManager.h" +#include "nm-vpnc-service.h" +#include "nm-utils.h" + + +/* + * send_config_error + * + * Notify nm-vpnc-service of a config error from 'vpnc'. + * + */ +static void send_config_error (DBusConnection *con, const char *item) +{ + DBusMessage *message; + + g_return_if_fail (con != NULL); + g_return_if_fail (item != NULL); + + if (!(message = dbus_message_new_method_call (NM_DBUS_SERVICE_VPNC, NM_DBUS_PATH_VPNC, NM_DBUS_INTERFACE_VPNC, "signalConfigError"))) + { + nm_warning ("send_config_error(): Couldn't allocate the dbus message"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &item, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("send_config_error(): could not send dbus message"); + + dbus_message_unref (message); +} + + +/* + * send_config_info + * + * Send IP config info to nm-vpnc-service + * + */ +static gboolean send_config_info (DBusConnection *con, const char *str_vpn_gateway, + const char *tundev, + const char *str_internal_ip4_address, + const char *str_internal_ip4_netmask, + const char *str_internal_ip4_dns, + const char *str_internal_ip4_nbns, + const char *cisco_def_domain, + const char *cisco_banner) +{ + DBusMessage * message; + struct in_addr temp_addr; + guint32 uint_vpn_gateway = 0; + guint32 uint_internal_ip4_address = 0; + guint32 uint_internal_ip4_netmask = 0xFFFFFFFF; /* Default mask of 255.255.255.255 */ + guint32 * uint_internal_ip4_dns = NULL; + guint32 uint_internal_ip4_dns_len = 0; + guint32 * uint_internal_ip4_nbns = NULL; + guint32 uint_internal_ip4_nbns_len = 0; + char ** split; + char ** item; + guint32 num_valid = 0, i; + gboolean success = FALSE; + + g_return_val_if_fail (con != NULL, FALSE); + + if (!(message = dbus_message_new_method_call (NM_DBUS_SERVICE_VPNC, NM_DBUS_PATH_VPNC, NM_DBUS_INTERFACE_VPNC, "signalIP4Config"))) + { + nm_warning ("send_config_error(): Couldn't allocate the dbus message"); + return FALSE; + } + + /* Convert IPv4 address arguments from strings into numbers */ + if (!inet_aton (str_vpn_gateway, &temp_addr)) + { + nm_warning ("nm-vpnc-service-vpnc-helper didn't receive a valid VPN Gateway from vpnc."); + send_config_error (con, "VPN Gateway"); + goto out; + } + uint_vpn_gateway = temp_addr.s_addr; + + if (!inet_aton (str_internal_ip4_address, &temp_addr)) + { + nm_warning ("nm-vpnc-service-vpnc-helper didn't receive a valid Internal IP4 Address from vpnc."); + send_config_error (con, "IP4 Address"); + goto out; + } + uint_internal_ip4_address = temp_addr.s_addr; + + if (strlen (str_internal_ip4_netmask) && inet_aton (str_internal_ip4_netmask, &temp_addr)) + uint_internal_ip4_netmask = temp_addr.s_addr; + + if (strlen (str_internal_ip4_dns)) + { + if ((split = g_strsplit (str_internal_ip4_dns, " ", -1))) + { + /* Pass over the array first to determine how many valid entries there are */ + num_valid = 0; + for (item = split; *item; item++) + if (inet_aton (*item, &temp_addr)) + num_valid++; + + /* Do the actual string->int conversion and assign to the array. */ + if (num_valid > 0) + { + uint_internal_ip4_dns = g_new0 (guint32, num_valid); + for (item = split, i = 0; *item; item++, i++) + if (inet_aton (*item, &temp_addr)) + uint_internal_ip4_dns[i] = temp_addr.s_addr; + } + + g_strfreev (split); + uint_internal_ip4_dns_len = num_valid; + } + } + if (!uint_internal_ip4_dns) + { + uint_internal_ip4_dns = g_malloc0 (sizeof (guint32)); + uint_internal_ip4_dns[0] = 0; + uint_internal_ip4_dns_len = 1; + } + + if (strlen (str_internal_ip4_nbns)) + { + if ((split = g_strsplit (str_internal_ip4_nbns, " ", -1))) + { + /* Pass over the array first to determine how many valid entries there are */ + num_valid = 0; + for (item = split; *item; item++) + if (inet_aton (*item, &temp_addr)) + num_valid++; + + /* Do the actual string->int conversion and assign to the array. */ + if (num_valid > 0) + { + uint_internal_ip4_nbns = g_new0 (guint32, num_valid); + for (item = split, i = 0; *item; item++, i++) + if (inet_aton (*item, &temp_addr)) + uint_internal_ip4_nbns[i] = temp_addr.s_addr; + } + + g_strfreev (split); + uint_internal_ip4_nbns_len = num_valid; + } + } + if (!uint_internal_ip4_nbns) + { + uint_internal_ip4_nbns = g_malloc0 (sizeof (guint32)); + uint_internal_ip4_nbns[0] = 0; + uint_internal_ip4_nbns_len = 1; + } + + dbus_message_append_args (message, DBUS_TYPE_UINT32, &uint_vpn_gateway, + DBUS_TYPE_STRING, &tundev, + DBUS_TYPE_UINT32, &uint_internal_ip4_address, + DBUS_TYPE_UINT32, &uint_internal_ip4_netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &uint_internal_ip4_dns, uint_internal_ip4_dns_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &uint_internal_ip4_nbns, uint_internal_ip4_nbns_len, + DBUS_TYPE_STRING, &cisco_def_domain, + DBUS_TYPE_STRING, &cisco_banner, DBUS_TYPE_INVALID); + if (dbus_connection_send (con, message, NULL)) + success = TRUE; + else + nm_warning ("send_config_error(): could not send dbus message"); + + dbus_message_unref (message); + +out: + return success; +} + + +/* + * Environment variables passed back from 'vpnc': + * + * VPNGATEWAY -- vpn gateway address (always present) + * TUNDEV -- tunnel device (always present) + * INTERNAL_IP4_ADDRESS -- address (always present) + * INTERNAL_IP4_NETMASK -- netmask (often unset) + * INTERNAL_IP4_DNS -- list of dns serverss + * INTERNAL_IP4_NBNS -- list of wins servers + * CISCO_DEF_DOMAIN -- default domain name + * CISCO_BANNER -- banner from server + * + */ + +/* + * main + * + */ +int main( int argc, char *argv[] ) +{ + DBusConnection * con; + DBusError error; + char * vpn_gateway = NULL; + char * tundev = NULL; + char * internal_ip4_address = NULL; + char * internal_ip4_netmask = NULL; + char * internal_ip4_dns = NULL; + char * internal_ip4_nbns = NULL; + char * cisco_def_domain = NULL; + char * cisco_banner = NULL; + + g_type_init (); + if (!g_thread_supported ()) + g_thread_init (NULL); + + dbus_error_init (&error); + con = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if ((con == NULL) || dbus_error_is_set (&error)) + { + nm_warning ("Could not get the system bus. Make sure the message bus daemon is running?"); + exit (1); + } + dbus_connection_set_exit_on_disconnect (con, FALSE); + + vpn_gateway = getenv ("VPNGATEWAY"); + tundev = getenv ("TUNDEV"); + internal_ip4_address = getenv ("INTERNAL_IP4_ADDRESS"); + internal_ip4_netmask = getenv ("INTERNAL_IP4_NETMASK"); + internal_ip4_dns = getenv ("INTERNAL_IP4_DNS"); + internal_ip4_nbns = getenv ("INTERNAL_IP4_NBNS"); + cisco_def_domain = getenv ("CISCO_DEF_DOMAIN"); + cisco_banner = getenv ("CISCO_BANNER"); + +#if 0 + file = fopen ("/tmp/vpnstuff", "w"); + fprintf (file, "VPNGATEWAY: '%s'\n", vpn_gateway); + fprintf (file, "TUNDEF: '%s'\n", tundev); + fprintf (file, "INTERNAL_IP4_ADDRESS: '%s'\n", internal_ip4_address); + fprintf (file, "INTERNAL_IP4_NETMASK: '%s'\n", internal_ip4_netmask); + fprintf (file, "INTERNAL_IP4_DNS: '%s'\n", internal_ip4_dns); + fprintf (file, "INTERNAL_IP4_NBNS: '%s'\n", internal_ip4_nbns); + fprintf (file, "CISCO_DEF_DOMAIN: '%s'\n", cisco_def_domain); + fprintf (file, "CISCO_BANNER: '%s'\n", cisco_banner); + fclose (file); +#endif + + if (!vpn_gateway) + { + nm_warning ("nm-vpnc-service-vpnc-helper didn't receive a VPN Gateway from vpnc."); + send_config_error (con, "VPN Gateway"); + exit (1); + } + if (!tundev || !g_utf8_validate (tundev, -1, NULL)) + { + nm_warning ("nm-vpnc-service-vpnc-helper didn't receive a Tunnel Device from vpnc, or the tunnel device was not valid UTF-8."); + send_config_error (con, "Tunnel Device"); + exit (1); + } + if (!internal_ip4_address) + { + nm_warning ("nm-vpnc-service-vpnc-helper didn't receive an Internal IP4 Address from vpnc."); + send_config_error (con, "IP4 Address"); + exit (1); + } + + if (!internal_ip4_netmask) + internal_ip4_netmask = g_strdup (""); + if (!internal_ip4_dns) + internal_ip4_dns = g_strdup (""); + if (!internal_ip4_nbns) + internal_ip4_nbns = g_strdup (""); + + /* Ensure strings from network are UTF-8 */ + if (cisco_def_domain && !g_utf8_validate (cisco_def_domain, -1, NULL)) + { + if (!(cisco_def_domain = g_convert (cisco_def_domain, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL))) + cisco_def_domain = g_convert (cisco_def_domain, -1, "C", "UTF-8", NULL, NULL, NULL); + } + if (!cisco_def_domain) + cisco_def_domain = g_strdup (""); + + if (cisco_banner && !g_utf8_validate (cisco_banner, -1, NULL)) + { + if (!(cisco_banner = g_convert (cisco_banner, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL))) + cisco_banner = g_convert (cisco_banner, -1, "C", "UTF-8", NULL, NULL, NULL); + } + if (!cisco_banner) + cisco_banner = g_strdup (""); + + /* Send the config info to nm-vpnc-service */ + if (!send_config_info (con, vpn_gateway, tundev, internal_ip4_address, internal_ip4_netmask, + internal_ip4_dns, internal_ip4_nbns, cisco_def_domain, cisco_banner)) + { + exit (1); + } + + exit (0); +} + diff --git a/vpn-daemons/vpnc/nm-vpnc-service.c b/vpn-daemons/vpnc/nm-vpnc-service.c new file mode 100644 index 000000000..8969063fd --- /dev/null +++ b/vpn-daemons/vpnc/nm-vpnc-service.c @@ -0,0 +1,1007 @@ +/* nm-vpnc-service - vpnc integration with NetworkManager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-vpnc-service.h" +#include "nm-utils.h" + +#define VPNC_BINARY_PATH_DEFAULT "/usr/sbin/vpnc" +#define NM_VPNC_HELPER_PATH BINDIR"/nm-vpnc-service-vpnc-helper" +#define NM_VPNC_PID_FILE_PATH LOCALSTATEDIR"/run/vpnc/pid" +#define NM_VPNC_CONFIG_FILE_PATH LOCALSTATEDIR"/run/vpnc/nm-vpnc-service-vpnc.conf" + +typedef struct NmVpncData +{ + GMainLoop * loop; + DBusConnection * con; + NMVPNState state; + GPid pid; + guint quit_timer; + guint helper_timer; +} NmVpncData; + + +static gboolean nm_vpnc_dbus_handle_stop_vpn (NmVpncData *data); + + +/* + * nm_dbus_create_error_message + * + * Make a DBus error message + * + */ +static DBusMessage *nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace, + const char *exception, const char *format, ...) +{ + char *exception_text; + DBusMessage *reply_message; + va_list args; + char error_text[512]; + + va_start (args, format); + vsnprintf (error_text, 512, format, args); + va_end (args); + + exception_text = g_strdup_printf ("%s.%s", exception_namespace, exception); + reply_message = dbus_message_new_error (message, exception_text, error_text); + g_free (exception_text); + + return (reply_message); +} + + +/* + * nm_vpnc_dbus_signal_login_failed + * + * Signal the bus that VPN login failed. + * + */ +static void nm_vpnc_dbus_signal_login_failed (NmVpncData *data) +{ + DBusMessage *message; + const char *error_msg = "The VPN login failed because the user name and password were not accepted."; + + g_return_if_fail (data != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPNC, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID); + if (!dbus_connection_send (data->con, message, NULL)) + nm_warning ("Could not raise the signal!"); + + dbus_message_unref (message); +} + + +/* + * nm_vpnc_dbus_signal_state_change + * + * Signal the bus that our state changed. + * + */ +static void nm_vpnc_dbus_signal_state_change (NmVpncData *data, NMVPNState old_state) +{ + DBusMessage *message; + + g_return_if_fail (data != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_VPNC, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_SIGNAL_STATE_CHANGE))) + { + nm_warning ("nm_vpnc_dbus_signal_state_change(): Not enough memory for new dbus message!"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_UINT32, &old_state, DBUS_TYPE_UINT32, &(data->state), DBUS_TYPE_INVALID); + + if (!dbus_connection_send (data->con, message, NULL)) + nm_warning ("nm_vpnc_dbus_signal_state_change(): Could not raise the signal!"); + + dbus_message_unref (message); +} + + +/* + * nm_vpnc_set_state + * + * Set our state and make sure to signal the bus. + * + */ +static void nm_vpnc_set_state (NmVpncData *data, NMVPNState new_state) +{ + NMVPNState old_state; + + g_return_if_fail (data != NULL); + + old_state = data->state; + data->state = new_state; + nm_vpnc_dbus_signal_state_change (data, old_state); +} + + +/* + * nm_vpnc_quit_timer_cb + * + * Callback to quit nm-vpnc-service after a certain period of time. + * + */ +static gboolean nm_vpnc_quit_timer_cb (NmVpncData *data) +{ + data->quit_timer = 0; + + g_return_val_if_fail (data != NULL, FALSE); + + g_main_loop_quit (data->loop); + + return FALSE; +} + + +/* + * nm_vpnc_schedule_quit_timer + * + * If vpnc isn't running, and we haven't been asked to do anything in a while, + * then we just exit since NetworkManager will re-launch us later. + * + */ +static void nm_vpnc_schedule_quit_timer (NmVpncData *data, guint interval) +{ + g_return_if_fail (data != NULL); + + if (data->quit_timer == 0) + data->quit_timer = g_timeout_add (interval, (GSourceFunc) nm_vpnc_quit_timer_cb, data); +} + + +/* + * nm_vpnc_cancel_quit_timer + * + * Cancel a quit timer that we've scheduled before. + * + */ +static void nm_vpnc_cancel_quit_timer (NmVpncData *data) +{ + g_return_if_fail (data != NULL); + + if (data->quit_timer > 0) + g_source_remove (data->quit_timer); +} + + +/* + * nm_vpnc_helper_timer_cb + * + * If we haven't received the IP4 config info from the helper before the timeout + * occurs, we kill vpnc. + * + */ +static gboolean nm_vpnc_helper_timer_cb (NmVpncData *data) +{ + data->helper_timer = 0; + + g_return_val_if_fail (data != NULL, FALSE); + + nm_vpnc_dbus_handle_stop_vpn (data); + + return FALSE; +} + + +/* + * nm_vpnc_schedule_helper_timer + * + * Once vpnc is running, we wait for the helper to return the IP4 configuration + * information to us. If we don't receive that information within 7 seconds, + * we kill vpnc. + * + */ +static void nm_vpnc_schedule_helper_timer (NmVpncData *data) +{ + g_return_if_fail (data != NULL); + + if (data->helper_timer == 0) + data->helper_timer = g_timeout_add (7000, (GSourceFunc) nm_vpnc_helper_timer_cb, data); +} + + +/* + * nm_vpnc_cancel_helper_timer + * + * Cancel a helper timer that we've scheduled before. + * + */ +static void nm_vpnc_cancel_helper_timer (NmVpncData *data) +{ + g_return_if_fail (data != NULL); + + if (data->helper_timer > 0) + g_source_remove (data->helper_timer); +} + + +/* + * vpnc_watch_cb + * + * Watch our child vpnc process and get notified of events from it. + * + */ +static void vpnc_watch_cb (GPid pid, gint status, gpointer user_data) +{ + guint error = -1; + + NmVpncData *data = (NmVpncData *)user_data; + + if (WIFEXITED (status)) + { + error = WEXITSTATUS (status); + nm_warning ("vpnc exited with error code %d", error); + } + else if (WIFSTOPPED (status)) + nm_warning ("vpnc stopped unexpectedly with signal %d", WSTOPSIG (status)); + else if (WIFSIGNALED (status)) + nm_warning ("vpnc died with signal %d", WTERMSIG (status)); + else + nm_warning ("vpnc died from an unknown cause"); + + /* Reap child if needed. */ + waitpid (data->pid, NULL, WNOHANG); + data->pid = 0; + + /* Must be after data->state is set since signals use data->state */ + switch (error) + { + case 2: /* Couldn't log in */ + nm_vpnc_dbus_signal_login_failed (data); + break; + + case 1: /* Other error (couldn't bind to address, etc) */ + break; + + case 0: /* Success, vpnc has daemonized */ + { + GPid daemon_pid; + char *contents; + + /* Grab the vpnc daemon's PID from its pidfile */ + if (g_file_get_contents (NM_VPNC_PID_FILE_PATH, &contents, NULL, NULL)) + { + data->pid = atoi (g_strstrip (contents)); + nm_info ("vpnc daemon's PID is %d\n", data->pid); + g_free (contents); + } + } + break; + + default: + break; + } + + unlink (NM_VPNC_CONFIG_FILE_PATH); + + /* If vpnc did not daemonize (due to errors), we quit after a bit */ + if (data->pid <= 0) + { + nm_vpnc_set_state (data, NM_VPN_STATE_STOPPED); + unlink (NM_VPNC_PID_FILE_PATH); + + nm_vpnc_schedule_quit_timer (data, 10000); + } + + /* State change from STARTING->STARTED happens when we get successful + * ip4 config info from the helper. + */ +} + + +/* + * nm_vpnc_start_vpn_binary + * + * Start the vpnc binary with a set of arguments and a config file. + * + */ +static gboolean nm_vpnc_start_vpnc_binary (NmVpncData *data) +{ + GPid pid; + const char * vpnc_binary; + GPtrArray * vpnc_argv; + GError * error; + gboolean success = FALSE; + GSource * vpnc_watch; + + g_return_val_if_fail (data != NULL, FALSE); + + data->pid = 0; + + unlink (NM_VPNC_PID_FILE_PATH); + + vpnc_argv = g_ptr_array_new (); + vpnc_binary = g_getenv ("VPNC_BINARY_PATH") ? g_getenv ("VPNC_BINARY_PATH") : VPNC_BINARY_PATH_DEFAULT; + g_ptr_array_add (vpnc_argv, (char *) vpnc_binary); + g_ptr_array_add (vpnc_argv, "--script"); + g_ptr_array_add (vpnc_argv, NM_VPNC_HELPER_PATH); + g_ptr_array_add (vpnc_argv, "--pid-file"); + g_ptr_array_add (vpnc_argv, NM_VPNC_PID_FILE_PATH); + g_ptr_array_add (vpnc_argv, NM_VPNC_CONFIG_FILE_PATH); + g_ptr_array_add (vpnc_argv, NULL); + + if (!g_spawn_async (NULL, (char **) vpnc_argv->pdata, NULL, + G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) + { + g_ptr_array_free (vpnc_argv, TRUE); + nm_warning ("vpnc failed to start. error: '%s'", error->message); + return FALSE; + } + g_ptr_array_free (vpnc_argv, TRUE); + + nm_info ("vpnc started with pid %d", pid); + + data->pid = pid; + vpnc_watch = g_child_watch_source_new (pid); + g_source_set_callback (vpnc_watch, (GSourceFunc) vpnc_watch_cb, data, NULL); + g_source_attach (vpnc_watch, NULL); + g_source_unref (vpnc_watch); + + nm_vpnc_schedule_helper_timer (data); + + return TRUE; +} + + +/* + * nm_vpnc_config_file_generate + * + * Generate a vpnc config file. + * + */ +static gboolean nm_vpnc_config_file_generate (const char *user_name, const char *password, const char **data_items, const int num_items) +{ + char *string; + int out_fd; + int i; + + g_return_val_if_fail (user_name != NULL, FALSE); + g_return_val_if_fail (password != NULL, FALSE); + g_return_val_if_fail (data_items != NULL, FALSE); + + unlink (NM_VPNC_CONFIG_FILE_PATH); + out_fd = open (NM_VPNC_CONFIG_FILE_PATH, O_WRONLY|O_CREAT|O_TRUNC, 0600); + if (out_fd < 0) + { + nm_warning ("Could not create vpnc config file '%s'.", NM_VPNC_CONFIG_FILE_PATH); + return FALSE; + } + + string = g_strdup_printf ("Xauth username %s\n", user_name); + write (out_fd, string, strlen (string)); + g_free (string); + + string = g_strdup_printf ("Xauth password %s\n", password); + write (out_fd, string, strlen (string)); + g_free (string); + + for (i = 0; i < num_items; i++) + { + char *temp = g_strdup_printf ("%s\n", data_items[i]); + write (out_fd, temp, strlen (temp)); + g_free (temp); + string++; + } + + close (out_fd); + + return TRUE; +} + + +/* + * nm_vpnc_dbus_handle_start_vpn + * + * Parse message arguments and start the VPN connection. + * + */ +static gboolean nm_vpnc_dbus_handle_start_vpn (DBusMessage *message, DBusMessage **reply, NmVpncData *data) +{ + const char **data_items = NULL; + int num_items = -1; + const char *name = NULL; + const char *user_name = NULL; + const char *password = NULL; + DBusError error; + gboolean success = FALSE; + + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (reply != NULL, FALSE); + + dbus_error_init (&error); + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_STRING, &password, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, &num_items, + DBUS_TYPE_INVALID)) + { + nm_warning ("Could not process the request because its arguments were invalid. dbus said: '%s'", error.message); + dbus_error_free (&error); + *reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_BAD_ARGUMENTS, + "Could not process the request because its arguments were invalid."); + goto out; + } + + /* Now we can finally try to activate the VPN */ + nm_vpnc_set_state (data, NM_VPN_STATE_STARTING); + if (nm_vpnc_config_file_generate (user_name, password, data_items, num_items)) + success = nm_vpnc_start_vpnc_binary (data); + if (!success) + nm_vpnc_set_state (data, NM_VPN_STATE_STOPPED); + +out: + return success; +} + + +/* + * nm_vpnc_dbus_handle_stop_vpn + * + * Stop the running vpnc dameon. + * + */ +static gboolean nm_vpnc_dbus_handle_stop_vpn (NmVpncData *data) +{ + g_return_val_if_fail (data != NULL, FALSE); + + if (data->pid > 0) + { + nm_vpnc_set_state (data, NM_VPN_STATE_STOPPING); + + kill (data->pid, SIGTERM); + nm_info ("Terminated vpnc daemon with PID %d.", data->pid); + data->pid = 0; + + nm_vpnc_set_state (data, NM_VPN_STATE_STOPPED); + nm_vpnc_schedule_quit_timer (data, 10000); + } + + return TRUE; +} + + +/* + * nm_vpnc_dbus_start_vpn + * + * Begin a VPN connection. + * + */ +static DBusMessage *nm_vpnc_dbus_start_vpn (DBusConnection *con, DBusMessage *message, NmVpncData *data) +{ + DBusMessage *reply = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (con != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + switch (data->state) + { + case NM_VPN_STATE_STARTING: + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_STARTING_IN_PROGRESS, + "Could not process the request because the VPN connection is already being started."); + break; + + case NM_VPN_STATE_STARTED: + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_ALREADY_STARTED, + "Could not process the request because a VPN connection was already active."); + break; + + case NM_VPN_STATE_STOPPING: + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_STOPPING_IN_PROGRESS, + "Could not process the request because the VPN connection is being stopped."); + break; + + case NM_VPN_STATE_STOPPED: + nm_vpnc_cancel_quit_timer (data); + nm_vpnc_dbus_handle_start_vpn (message, &reply, data); + if (!reply) + reply = dbus_message_new_method_return (message); + break; + + default: + g_assert_not_reached(); + break; + } + +out: + return reply; +} + + +/* + * nm_vpnc_dbus_stop_vpn + * + * Terminate a VPN connection. + * + */ +static DBusMessage *nm_vpnc_dbus_stop_vpn (DBusConnection *con, DBusMessage *message, NmVpncData *data) +{ + DBusMessage *reply = NULL; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (con != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + switch (data->state) + { + case NM_VPN_STATE_STOPPING: + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_STOPPING_IN_PROGRESS, + "Could not process the request because the VPN connection is already being stopped."); + break; + + case NM_VPN_STATE_STOPPED: + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_ALREADY_STOPPED, + "Could not process the request because no VPN connection was active."); + break; + + case NM_VPN_STATE_STARTING: + case NM_VPN_STATE_STARTED: + nm_vpnc_dbus_handle_stop_vpn (data); + reply = dbus_message_new_method_return (message); + break; + + default: + g_assert_not_reached(); + break; + } + +out: + return reply; +} + + +/* + * nm_vpnc_dbus_get_state + * + * Return some state information to NetworkManager. + * + */ +static DBusMessage *nm_vpnc_dbus_get_state (DBusConnection *con, DBusMessage *message, NmVpncData *data) +{ + DBusMessage *reply = NULL; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (con != NULL, NULL); + g_return_val_if_fail (message != NULL, NULL); + + if ((reply = dbus_message_new_method_return (message))) + dbus_message_append_args (reply, DBUS_TYPE_UINT32, &(data->state), DBUS_TYPE_INVALID); + + return reply; +} + + +/* + * nm_vpnc_dbus_process_helper_config_error + * + * Signal the bus that the helper could not get all the configuration information + * it needed. + * + */ +static void nm_vpnc_dbus_process_helper_config_error (DBusConnection *con, DBusMessage *message, NmVpncData *data) +{ + char *error_item; + + g_return_if_fail (data != NULL); + g_return_if_fail (con != NULL); + g_return_if_fail (message != NULL); + + /* Only accept the config info if we're in STARTING state */ + if (data->state != NM_VPN_STATE_STARTING) + return; + + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &error_item, DBUS_TYPE_INVALID)) + { + nm_warning ("vpnc helper did not receive adequate configuration information from vpnc. It is missing '%s'.", error_item); + /* Signal NetworkManager */ + } + + nm_vpnc_cancel_helper_timer (data); + nm_vpnc_dbus_handle_stop_vpn (data); +} + + +/* + * Prints config returned from vpnc-helper + */ +static void print_vpn_config (guint32 ip4_vpn_gateway, + const char *tundev, + guint32 ip4_internal_address, + gint32 ip4_internal_netmask, + guint32 *ip4_internal_dns, + guint32 ip4_internal_dns_len, + guint32 *ip4_internal_nbns, + guint32 ip4_internal_nbns_len, + const char *cisco_def_domain, + const char *cisco_banner) +{ + struct in_addr temp_addr; + guint32 i; + + temp_addr.s_addr = ip4_vpn_gateway; + nm_info ("VPN Gateway: %s", inet_ntoa (temp_addr)); + nm_info ("Tunnel Device: %s", tundev); + temp_addr.s_addr = ip4_internal_address; + nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); + temp_addr.s_addr = ip4_internal_netmask; + nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); + + for (i = 0; i < ip4_internal_dns_len; i++) + { + if (ip4_internal_dns[i] != 0) + { + temp_addr.s_addr = ip4_internal_dns[i]; + nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); + } + } + + for (i = 0; i < ip4_internal_nbns_len; i++) + { + if (ip4_internal_nbns[i] != 0) + { + temp_addr.s_addr = ip4_internal_nbns[i]; + nm_info ("Internal IP4 NBNS: %s", inet_ntoa (temp_addr)); + } + } + + nm_info ("Cisco Default Domain: '%s'", cisco_def_domain); + nm_info ("Cisco Banner:"); + nm_info ("-----------------------------------------"); + nm_info ("%s", cisco_banner); + nm_info ("-----------------------------------------"); +} + +/* + * nm_vpnc_dbus_process_helper_ip4_config + * + * Signal the bus + * + */ +static void nm_vpnc_dbus_process_helper_ip4_config (DBusConnection *con, DBusMessage *message, NmVpncData *data) +{ + guint32 ip4_vpn_gateway; + char * tundev; + guint32 ip4_internal_address; + guint32 ip4_internal_netmask; + guint32 * ip4_internal_dns; + guint32 ip4_internal_dns_len; + guint32 * ip4_internal_nbns; + guint32 ip4_internal_nbns_len; + char * cisco_def_domain; + char * cisco_banner; + gboolean success = FALSE; + + g_return_if_fail (data != NULL); + g_return_if_fail (con != NULL); + g_return_if_fail (message != NULL); + + /* Only accept the config info if we're in STARTING state */ + if (data->state != NM_VPN_STATE_STARTING) + return; + + nm_vpnc_cancel_helper_timer (data); + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ip4_vpn_gateway, + DBUS_TYPE_STRING, &tundev, + DBUS_TYPE_UINT32, &ip4_internal_address, + DBUS_TYPE_UINT32, &ip4_internal_netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_dns, &ip4_internal_dns_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_nbns, &ip4_internal_nbns_len, + DBUS_TYPE_STRING, &cisco_def_domain, + DBUS_TYPE_STRING, &cisco_banner, DBUS_TYPE_INVALID)) + { + DBusMessage *signal; + +#if 0 + print_vpn_config (ip4_vpn_gateway, tundev, ip4_internal_address, ip4_internal_netmask, + ip4_internal_dns, ip4_internal_dns_len, ip4_internal_nbns, ip4_internal_nbns_len, + cisco_def_domain, cisco_banner); +#endif + + if (!(signal = dbus_message_new_signal (NM_DBUS_PATH_VPNC, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_SIGNAL_IP4_CONFIG))) + { + nm_warning ("Not enough memory for new dbus message!"); + goto out; + } + + dbus_message_append_args (signal, DBUS_TYPE_UINT32, &ip4_vpn_gateway, + DBUS_TYPE_STRING, &tundev, + DBUS_TYPE_UINT32, &ip4_internal_address, + DBUS_TYPE_UINT32, &ip4_internal_netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_dns, ip4_internal_dns_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_nbns, ip4_internal_nbns_len, + DBUS_TYPE_STRING, &cisco_def_domain, + DBUS_TYPE_STRING, &cisco_banner, DBUS_TYPE_INVALID); + if (!dbus_connection_send (data->con, signal, NULL)) + { + nm_warning ("Could not raise the "NM_DBUS_VPN_SIGNAL_IP4_CONFIG" signal!"); + goto out; + } + + dbus_message_unref (signal); + success = TRUE; + } + +out: + if (!success) + { + nm_warning ("Received invalid IP4 Config information from helper, terminating vpnc."); + nm_vpnc_dbus_handle_stop_vpn (data); + } +} + + +/* + * nm_vpnc_dbus_message_handler + * + * Handle requests for our services. + * + */ +static DBusHandlerResult nm_vpnc_dbus_message_handler (DBusConnection *con, DBusMessage *message, void *user_data) +{ + NmVpncData *data = (NmVpncData *)user_data; + const char *method; + const char *path; + DBusMessage *reply = NULL; + gboolean handled = TRUE; + + g_return_val_if_fail (data != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (con != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + method = dbus_message_get_member (message); + path = dbus_message_get_path (message); + + /* nm_info ("nm_vpnc_dbus_message_handler() got method '%s' for path '%s'.", method, path); */ + + /* If we aren't ready to accept dbus messages, don't */ + if ((data->state == NM_VPN_STATE_INIT) || (data->state == NM_VPN_STATE_SHUTDOWN)) + { + nm_warning ("Received dbus messages but couldn't handle them due to INIT or SHUTDOWN states."); + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPNC, NM_DBUS_VPN_WRONG_STATE, + "Could not process the request due to current state of STATE_INIT or STATE_SHUTDOWN."); + goto reply; + } + + if (strcmp ("startConnection", method) == 0) + reply = nm_vpnc_dbus_start_vpn (con, message, data); + else if (strcmp ("stopConnection", method) == 0) + reply = nm_vpnc_dbus_stop_vpn (con, message, data); + else if (strcmp ("getState", method) == 0) + reply = nm_vpnc_dbus_get_state (con, message, data); + else if (strcmp ("signalConfigError", method) == 0) + nm_vpnc_dbus_process_helper_config_error (con, message, data); + else if (strcmp ("signalIP4Config", method) == 0) + nm_vpnc_dbus_process_helper_ip4_config (con, message, data); + else + handled = FALSE; + +reply: + if (reply) + { + dbus_connection_send (con, reply, NULL); + dbus_message_unref (reply); + } + + return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); +} + + +/* + * nm_vpnc_dbus_filter + * + * Handle signals from the bus, like NetworkManager network state + * signals. + * + */ +static DBusHandlerResult nm_vpnc_dbus_filter (DBusConnection *con, DBusMessage *message, void *user_data) +{ + NmVpncData *data = (NmVpncData *)user_data; + gboolean handled = FALSE; + DBusError error; + + g_return_val_if_fail (data != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (con != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) + { + char *service; + char *old_owner; + char *new_owner; + + dbus_error_init (&error); + if ( dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) + { + gboolean old_owner_good = (old_owner && (strlen (old_owner) > 0)); + gboolean new_owner_good = (new_owner && (strlen (new_owner) > 0)); + + if ((!old_owner_good && new_owner_good) && (strcmp (service, NM_DBUS_SERVICE) == 0)) /* Equivalent to old ServiceCreated signal */ + { + } + else if ((old_owner_good && !new_owner_good) && (strcmp (service, NM_DBUS_SERVICE) == 0)) /* Equivalent to old ServiceDeleted signal */ + { + /* If NM goes away, we don't stick around */ + nm_vpnc_dbus_handle_stop_vpn (data); + } + } + } + else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNoLongerActive")) + { + /* If the active device goes down our VPN is certainly not going to work. */ + nm_vpnc_dbus_handle_stop_vpn (data); + } + + return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); +} + + +/* + * nm_vpnc_dbus_init + * + * Grab our connection to the system bus, return NULL if anything goes wrong. + * + */ +DBusConnection *nm_vpnc_dbus_init (NmVpncData *data) +{ + DBusConnection *connection = NULL; + DBusError error; + DBusObjectPathVTable vtable = { NULL, &nm_vpnc_dbus_message_handler, NULL, NULL, NULL, NULL }; + + g_return_val_if_fail (data != NULL, NULL); + + dbus_error_init (&error); + if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) + { + nm_warning ("Error connecting to system bus: '%s'", error.message); + goto out; + } + + dbus_connection_setup_with_g_main (connection, NULL); + + dbus_error_init (&error); + dbus_bus_request_name (connection, NM_DBUS_SERVICE_VPNC, 0, &error); + if (dbus_error_is_set (&error)) + { + nm_warning ("Could not acquire the dbus service. dbus_bus_request_name() says: '%s'", error.message); + goto out; + } + + if (!dbus_connection_register_object_path (connection, NM_DBUS_PATH_VPNC, &vtable, data)) + { + nm_warning ("Could not register a dbus handler for nm-vpnc-service. Not enough memory?"); + return NULL; + } + + if (!dbus_connection_add_filter (connection, nm_vpnc_dbus_filter, data, NULL)) + return NULL; + + dbus_error_init (&error); + dbus_bus_add_match (connection, + "type='signal'," + "interface='" NM_DBUS_INTERFACE "'," + "sender='" NM_DBUS_SERVICE "'," + "path='" NM_DBUS_PATH "'", + &error); + if (dbus_error_is_set (&error)) + goto out; + + dbus_bus_add_match (connection, + "type='signal'," + "interface='" DBUS_INTERFACE_DBUS "'," + "sender='" DBUS_SERVICE_DBUS "'", + &error); + if (dbus_error_is_set (&error)) + goto out; + +out: + if (dbus_error_is_set (&error)) + { + dbus_error_free (&error); + connection = NULL; + } + return connection; +} + +NmVpncData *vpn_data = NULL; + +static void sigterm_handler (int signum) +{ + nm_info ("nm-vpnc-service caught SIGINT/SIGTERM"); + + g_main_loop_quit (vpn_data->loop); +} + + +/* + * main + * + */ +int main( int argc, char *argv[] ) +{ + struct sigaction action; + sigset_t block_mask; + + g_type_init (); + if (!g_thread_supported ()) + g_thread_init (NULL); + + if (!(vpn_data = g_malloc0 (sizeof (NmVpncData)))) + { + nm_warning ("Not enough memory to initialize."); + exit (1); + } + vpn_data->state = NM_VPN_STATE_INIT; + + vpn_data->loop = g_main_loop_new (NULL, FALSE); + + system ("/sbin/modprobe tun"); + + if (!(vpn_data->con = nm_vpnc_dbus_init (vpn_data))) + exit (1); + + action.sa_handler = sigterm_handler; + sigemptyset (&block_mask); + action.sa_mask = block_mask; + action.sa_flags = 0; + sigaction (SIGINT, &action, NULL); + sigaction (SIGTERM, &action, NULL); + + nm_vpnc_set_state (vpn_data, NM_VPN_STATE_STOPPED); + g_main_loop_run (vpn_data->loop); + + nm_vpnc_dbus_handle_stop_vpn (vpn_data); + + g_main_loop_unref (vpn_data->loop); + g_free (vpn_data); + + exit (0); +} diff --git a/vpn-daemons/vpnc/nm-vpnc-service.conf b/vpn-daemons/vpnc/nm-vpnc-service.conf new file mode 100644 index 000000000..7942c217e --- /dev/null +++ b/vpn-daemons/vpnc/nm-vpnc-service.conf @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/vpn-daemons/vpnc/nm-vpnc-service.h b/vpn-daemons/vpnc/nm-vpnc-service.h new file mode 100644 index 000000000..819fc701b --- /dev/null +++ b/vpn-daemons/vpnc/nm-vpnc-service.h @@ -0,0 +1,29 @@ +/* nm-vpnc-service - vpnc integration with NetworkManager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_VPNC_SERVICE_H +#define NM_VPNC_SERVICE_H + +#define NM_DBUS_SERVICE_VPNC "org.freedesktop.vpnc" +#define NM_DBUS_INTERFACE_VPNC "org.freedesktop.vpnc" +#define NM_DBUS_PATH_VPNC "/org/freedesktop/vpnc" + +#endif diff --git a/vpn-daemons/vpnc/nm-vpnc-service.name b/vpn-daemons/vpnc/nm-vpnc-service.name new file mode 100644 index 000000000..4d79390a2 --- /dev/null +++ b/vpn-daemons/vpnc/nm-vpnc-service.name @@ -0,0 +1,2 @@ +service=org.freedesktop.vpnc +program=/usr/bin/nm-vpnc-service