Commit 1dfd32bd authored by Alexey Torkhov's avatar Alexey Torkhov

Initial copy from NetworkManager-pptp.

parents
# Temporary files
*~
*.swp
# Compiled files
*.o
*.la
*.lo
auth-dialog/nm-l2tp-auth-dialog
src/nm-l2tp-service
# Generated
nm-l2tp-service.name
src/nm-l2tp-pppd-service-glue.h
# GNU Autotools
.deps
.libs
aclocal.m4
autom4te.cache/
depcomp
compile
config.guess
config.h
config.h.in
config.h~
config.log
config.status
config.sub
configure
install-sh
intltool-extract.in
intltool-merge.in
intltool-update.in
libtool
ltmain.sh
m4/
Makefile
Makefile.in
missing
po/Makefile.in.in
po/POTFILES
po/stamp-it
stamp-h1
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src
if WITH_GNOME
SUBDIRS += common-gnome auth-dialog properties po
endif
dbusservicedir = $(sysconfdir)/dbus-1/system.d
dbusservice_DATA = nm-l2tp-service.conf
nmvpnservicedir = $(sysconfdir)/NetworkManager/VPN
nmvpnservice_DATA = nm-l2tp-service.name
desktopfile = nm-l2tp.desktop.in
iconfile = gnome-mime-application-x-l2tp-settings.png
if WITH_GNOME
# FIXME: uncomment when nmce gets --import support
#desktopdir = $(datadir)/applications
#desktop_in_files = $(desktopfile)
#desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
#@INTLTOOL_DESKTOP_RULE@
#icondir = $(datadir)/icons/hicolor/48x48/apps
#icon_DATA = $(iconfile)
endif
nm-l2tp-service.name: $(srcdir)/nm-l2tp-service.name.in
sed -e 's|[@]LIBEXECDIR[@]|$(libexecdir)|g' $< >$@
EXTRA_DIST = nm-l2tp-service.name.in \
$(dbusservice_DATA) \
$(desktopfile) \
$(iconfile) \
intltool-extract.in \
intltool-merge.in \
intltool-update.in
CLEANFILES = $(nmvpnservice_DATA) $(desktop_DATA) *~
DISTCLEANFILES = intltool-extract intltool-merge intltool-update
ACLOCAL_AMFLAGS = -I m4
INCLUDES = -I${top_srcdir}
libexec_PROGRAMS = nm-l2tp-auth-dialog
nm_l2tp_auth_dialog_CPPFLAGS = \
$(NM_UTILS_CFLAGS) \
$(GTHREAD_CFLAGS) \
$(GTK_CFLAGS) \
$(GCONF_CFLAGS) \
$(GNOMEKEYRING_CFLAGS) \
-DICONDIR=\""$(datadir)/pixmaps"\" \
-DGLADEDIR=\""$(gladedir)"\" \
-DBINDIR=\""$(bindir)"\" \
-DG_DISABLE_DEPRECATED \
-DGDK_DISABLE_DEPRECATED \
-DGNOME_DISABLE_DEPRECATED \
-DGNOMELOCALEDIR=\"$(datadir)/locale\" \
-DVERSION=\"$(VERSION)\"
nm_l2tp_auth_dialog_SOURCES = \
main.c \
gnome-two-password-dialog.c \
gnome-two-password-dialog.h
nm_l2tp_auth_dialog_LDADD = \
$(GTK_LIBS) \
$(GCONF_LIBS) \
$(top_builddir)/common-gnome/libnm-l2tp-common-gnome.la
CLEANFILES = *~
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gnome-password-dialog.c - A use password prompting dialog widget.
Copyright (C) 1999, 2000 Eazel, Inc.
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the ree Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library 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
Library 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Authors: Ramiro Estrugo <ramiro@eazel.com>
*/
#include <config.h>
#include "gnome-two-password-dialog.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
struct GnomeTwoPasswordDialogDetails
{
/* Attributes */
gboolean readonly_username;
gboolean readonly_domain;
gboolean show_username;
gboolean show_domain;
gboolean show_password;
gboolean show_password_secondary;
/* TODO: */
gboolean remember;
char *remember_label_text;
/* Internal widgetry and flags */
GtkWidget *username_entry;
GtkWidget *password_entry;
GtkWidget *password_entry_secondary;
GtkWidget *domain_entry;
GtkWidget *table_alignment;
GtkWidget *table;
GtkWidget *remember_session_button;
GtkWidget *remember_forever_button;
GtkWidget *radio_vbox;
GtkWidget *connect_with_no_userpass_button;
GtkWidget *connect_with_userpass_button;
gboolean anon_support_on;
char *secondary_password_label;
};
/* Caption table rows indices */
static const guint CAPTION_TABLE_USERNAME_ROW = 0;
static const guint CAPTION_TABLE_PASSWORD_ROW = 1;
/* GnomeTwoPasswordDialogClass methods */
static void gnome_two_password_dialog_class_init (GnomeTwoPasswordDialogClass *password_dialog_class);
static void gnome_two_password_dialog_init (GnomeTwoPasswordDialog *password_dialog);
/* GObjectClass methods */
static void gnome_two_password_dialog_finalize (GObject *object);
/* GtkDialog callbacks */
static void dialog_show_callback (GtkWidget *widget,
gpointer callback_data);
static void dialog_close_callback (GtkWidget *widget,
gpointer callback_data);
static gpointer parent_class;
GType
gnome_two_password_dialog_get_type (void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof (GnomeTwoPasswordDialogClass),
NULL, NULL,
(GClassInitFunc) gnome_two_password_dialog_class_init,
NULL, NULL,
sizeof (GnomeTwoPasswordDialog), 0,
(GInstanceInitFunc) gnome_two_password_dialog_init,
NULL
};
type = g_type_register_static (gtk_dialog_get_type(),
"GnomeTwoPasswordDialog",
&info, 0);
parent_class = g_type_class_ref (gtk_dialog_get_type());
}
return type;
}
static void
gnome_two_password_dialog_class_init (GnomeTwoPasswordDialogClass * klass)
{
G_OBJECT_CLASS (klass)->finalize = gnome_two_password_dialog_finalize;
}
static void
gnome_two_password_dialog_init (GnomeTwoPasswordDialog *password_dialog)
{
password_dialog->details = g_new0 (GnomeTwoPasswordDialogDetails, 1);
password_dialog->details->show_username = TRUE;
password_dialog->details->show_password = TRUE;
password_dialog->details->show_password_secondary = TRUE;
password_dialog->details->anon_support_on = FALSE;
password_dialog->details->secondary_password_label = g_strdup ( _("_Secondary Password:") );
}
/* GObjectClass methods */
static void
gnome_two_password_dialog_finalize (GObject *object)
{
GnomeTwoPasswordDialog *password_dialog;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (object);
g_object_unref (password_dialog->details->username_entry);
g_object_unref (password_dialog->details->domain_entry);
g_object_unref (password_dialog->details->password_entry);
g_object_unref (password_dialog->details->password_entry_secondary);
g_free (password_dialog->details->remember_label_text);
g_free (password_dialog->details->secondary_password_label);
g_free (password_dialog->details);
if (G_OBJECT_CLASS (parent_class)->finalize != NULL)
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
/* GtkDialog callbacks */
static void
dialog_show_callback (GtkWidget *widget, gpointer callback_data)
{
GnomeTwoPasswordDialog *password_dialog;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (callback_data);
if (GTK_WIDGET_VISIBLE (password_dialog->details->username_entry) &&
!password_dialog->details->readonly_username) {
gtk_widget_grab_focus (password_dialog->details->username_entry);
} else if (GTK_WIDGET_VISIBLE (password_dialog->details->domain_entry) &&
!password_dialog->details->readonly_domain) {
gtk_widget_grab_focus (password_dialog->details->domain_entry);
} else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry)) {
gtk_widget_grab_focus (password_dialog->details->password_entry);
} else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary)) {
gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
}
}
static void
dialog_close_callback (GtkWidget *widget, gpointer callback_data)
{
gtk_widget_hide (widget);
}
static void
userpass_radio_button_clicked (GtkWidget *widget, gpointer callback_data)
{
GnomeTwoPasswordDialog *password_dialog;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (callback_data);
if (widget == password_dialog->details->connect_with_no_userpass_button) {
gtk_widget_set_sensitive (
password_dialog->details->table, FALSE);
}
else { /* the other button */
gtk_widget_set_sensitive (
password_dialog->details->table, TRUE);
}
}
static void
add_row (GtkWidget *table, int row, const char *label_text, GtkWidget *entry)
{
GtkWidget *label;
label = gtk_label_new_with_mnemonic (label_text);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach_defaults (GTK_TABLE (table), label,
0, 1, row, row + 1);
gtk_table_attach_defaults (GTK_TABLE (table), entry,
1, 2, row, row + 1);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
}
static void
remove_child (GtkWidget *child, GtkWidget *table)
{
gtk_container_remove (GTK_CONTAINER (table), child);
}
static void
add_table_rows (GnomeTwoPasswordDialog *password_dialog)
{
int row;
GtkWidget *table;
int offset;
if (password_dialog->details->anon_support_on) {
offset = 12;
}
else {
offset = 0;
}
gtk_alignment_set_padding (GTK_ALIGNMENT (password_dialog->details->table_alignment),
0, 0, offset, 0);
table = password_dialog->details->table;
/* This will not kill the entries, since they are ref:ed */
gtk_container_foreach (GTK_CONTAINER (table),
(GtkCallback)remove_child, table);
row = 0;
if (password_dialog->details->show_username)
add_row (table, row++, _("_Username:"), password_dialog->details->username_entry);
if (password_dialog->details->show_domain)
add_row (table, row++, _("_Domain:"), password_dialog->details->domain_entry);
if (password_dialog->details->show_password)
add_row (table, row++, _("_Password:"), password_dialog->details->password_entry);
if (password_dialog->details->show_password_secondary)
add_row (table, row++, password_dialog->details->secondary_password_label,
password_dialog->details->password_entry_secondary);
gtk_widget_show_all (table);
}
static void
username_entry_activate (GtkWidget *widget, GtkWidget *dialog)
{
GnomeTwoPasswordDialog *password_dialog;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (dialog);
if (GTK_WIDGET_VISIBLE (password_dialog->details->domain_entry) &&
GTK_WIDGET_SENSITIVE (password_dialog->details->domain_entry))
gtk_widget_grab_focus (password_dialog->details->domain_entry);
else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry) &&
GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry))
gtk_widget_grab_focus (password_dialog->details->password_entry);
else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary) &&
GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry_secondary))
gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
}
static void
domain_entry_activate (GtkWidget *widget, GtkWidget *dialog)
{
GnomeTwoPasswordDialog *password_dialog;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (dialog);
if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry) &&
GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry))
gtk_widget_grab_focus (password_dialog->details->password_entry);
else if (GTK_WIDGET_VISIBLE (password_dialog->details->password_entry_secondary) &&
GTK_WIDGET_SENSITIVE (password_dialog->details->password_entry_secondary))
gtk_widget_grab_focus (password_dialog->details->password_entry_secondary);
}
/* Public GnomeTwoPasswordDialog methods */
GtkWidget *
gnome_two_password_dialog_new (const char *dialog_title,
const char *message,
const char *username,
const char *password,
gboolean readonly_username)
{
GnomeTwoPasswordDialog *password_dialog;
GtkDialog *dialog;
GtkWidget *table;
GtkLabel *message_label;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *main_vbox;
GtkWidget *dialog_icon;
GSList *group;
password_dialog = GNOME_TWO_PASSWORD_DIALOG (gtk_widget_new (gnome_two_password_dialog_get_type (), NULL));
dialog = GTK_DIALOG (password_dialog);
gtk_window_set_title (GTK_WINDOW (password_dialog), dialog_title);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_dialog_add_buttons (dialog,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (password_dialog), GTK_RESPONSE_OK);
/* Setup the dialog */
gtk_dialog_set_has_separator (dialog, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
gtk_window_set_position (GTK_WINDOW (password_dialog), GTK_WIN_POS_CENTER);
gtk_window_set_modal (GTK_WINDOW (password_dialog), TRUE);
g_signal_connect (password_dialog, "show",
G_CALLBACK (dialog_show_callback), password_dialog);
g_signal_connect (password_dialog, "close",
G_CALLBACK (dialog_close_callback), password_dialog);
/* the radio buttons for anonymous login */
password_dialog->details->connect_with_no_userpass_button =
gtk_radio_button_new_with_mnemonic (NULL, _("Connect _anonymously"));
group = gtk_radio_button_get_group (
GTK_RADIO_BUTTON (password_dialog->details->connect_with_no_userpass_button));
password_dialog->details->connect_with_userpass_button =
gtk_radio_button_new_with_mnemonic (
group, _("Connect as _user:"));
if (username != NULL && *username != 0) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_userpass_button), TRUE);
} else {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_no_userpass_button), TRUE);
}
password_dialog->details->radio_vbox = gtk_vbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (password_dialog->details->radio_vbox),
password_dialog->details->connect_with_no_userpass_button,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (password_dialog->details->radio_vbox),
password_dialog->details->connect_with_userpass_button,
FALSE, FALSE, 0);
g_signal_connect (password_dialog->details->connect_with_no_userpass_button, "clicked",
G_CALLBACK (userpass_radio_button_clicked), password_dialog);
g_signal_connect (password_dialog->details->connect_with_userpass_button, "clicked",
G_CALLBACK (userpass_radio_button_clicked), password_dialog);
/* The table that holds the captions */
password_dialog->details->table_alignment = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
password_dialog->details->table = table = gtk_table_new (3, 2, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 12);
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
gtk_container_add (GTK_CONTAINER (password_dialog->details->table_alignment), table);
password_dialog->details->username_entry = gtk_entry_new ();
password_dialog->details->domain_entry = gtk_entry_new ();
password_dialog->details->password_entry = gtk_entry_new ();
password_dialog->details->password_entry_secondary = gtk_entry_new ();
/* We want to hold on to these during the table rearrangement */
#if GLIB_CHECK_VERSION (2, 10, 0)
g_object_ref_sink (password_dialog->details->username_entry);
g_object_ref_sink (password_dialog->details->domain_entry);
g_object_ref_sink (password_dialog->details->password_entry);
g_object_ref_sink (password_dialog->details->password_entry_secondary);
#else
g_object_ref (password_dialog->details->username_entry);
gtk_object_sink (GTK_OBJECT (password_dialog->details->username_entry));
g_object_ref (password_dialog->details->domain_entry);
gtk_object_sink (GTK_OBJECT (password_dialog->details->domain_entry));
g_object_ref (password_dialog->details->password_entry);
gtk_object_sink (GTK_OBJECT (password_dialog->details->password_entry));
g_object_ref (password_dialog->details->password_entry_secondary);
gtk_object_sink (GTK_OBJECT (password_dialog->details->password_entry_secondary));
#endif
gtk_entry_set_visibility (GTK_ENTRY (password_dialog->details->password_entry), FALSE);
gtk_entry_set_visibility (GTK_ENTRY (password_dialog->details->password_entry_secondary), FALSE);
g_signal_connect (password_dialog->details->username_entry,
"activate",
G_CALLBACK (username_entry_activate),
password_dialog);
g_signal_connect (password_dialog->details->domain_entry,
"activate",
G_CALLBACK (domain_entry_activate),
password_dialog);
g_signal_connect_swapped (password_dialog->details->password_entry,
"activate",
G_CALLBACK (gtk_window_activate_default),
password_dialog);
g_signal_connect_swapped (password_dialog->details->password_entry_secondary,
"activate",
G_CALLBACK (gtk_window_activate_default),
password_dialog);
add_table_rows (password_dialog);
/* Adds some eye-candy to the dialog */
hbox = gtk_hbox_new (FALSE, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
dialog_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
gtk_misc_set_alignment (GTK_MISC (dialog_icon), 0.5, 0.0);
gtk_box_pack_start (GTK_BOX (hbox), dialog_icon, FALSE, FALSE, 0);
/* Fills the vbox */
main_vbox = gtk_vbox_new (FALSE, 18);
if (message) {
message_label = GTK_LABEL (gtk_label_new (message));
gtk_label_set_justify (message_label, GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (message_label, TRUE);
gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (message_label),
FALSE, FALSE, 0);
}
vbox = gtk_vbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->radio_vbox,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->table_alignment,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), main_vbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (password_dialog)->vbox),
hbox,
TRUE, /* expand */
TRUE, /* fill */
0); /* padding */
gtk_widget_show_all (GTK_DIALOG (password_dialog)->vbox);
password_dialog->details->remember_session_button =
gtk_check_button_new_with_mnemonic (_("_Remember passwords for this session"));
password_dialog->details->remember_forever_button =
gtk_check_button_new_with_mnemonic (_("_Save passwords in keyring"));
gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->remember_session_button,
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), password_dialog->details->remember_forever_button,
FALSE, FALSE, 0);
gnome_two_password_dialog_set_username (password_dialog, username);
gnome_two_password_dialog_set_password (password_dialog, password);
gnome_two_password_dialog_set_readonly_domain (password_dialog, readonly_username);
return GTK_WIDGET (password_dialog);
}
gboolean
gnome_two_password_dialog_run_and_block (GnomeTwoPasswordDialog *password_dialog)
{
gint button_clicked;
g_return_val_if_fail (password_dialog != NULL, FALSE);
g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), FALSE);
button_clicked = gtk_dialog_run (GTK_DIALOG (password_dialog));
gtk_widget_hide (GTK_WIDGET (password_dialog));
return button_clicked == GTK_RESPONSE_OK;
}
void
gnome_two_password_dialog_set_username (GnomeTwoPasswordDialog *password_dialog,
const char *username)
{
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
g_return_if_fail (password_dialog->details->username_entry != NULL);
gtk_entry_set_text (GTK_ENTRY (password_dialog->details->username_entry),
username?username:"");
}
void
gnome_two_password_dialog_set_password (GnomeTwoPasswordDialog *password_dialog,
const char *password)
{
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
gtk_entry_set_text (GTK_ENTRY (password_dialog->details->password_entry),
password ? password : "");
}
void
gnome_two_password_dialog_set_password_secondary (GnomeTwoPasswordDialog *password_dialog,
const char *password_secondary)
{
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
gtk_entry_set_text (GTK_ENTRY (password_dialog->details->password_entry_secondary),
password_secondary ? password_secondary : "");
}
void
gnome_two_password_dialog_set_domain (GnomeTwoPasswordDialog *password_dialog,
const char *domain)
{
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
g_return_if_fail (password_dialog->details->domain_entry != NULL);
gtk_entry_set_text (GTK_ENTRY (password_dialog->details->domain_entry),
domain ? domain : "");
}
void
gnome_two_password_dialog_set_show_username (GnomeTwoPasswordDialog *password_dialog,
gboolean show)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
show = !!show;
if (password_dialog->details->show_username != show) {
password_dialog->details->show_username = show;
add_table_rows (password_dialog);
}
}
void
gnome_two_password_dialog_set_show_domain (GnomeTwoPasswordDialog *password_dialog,
gboolean show)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
show = !!show;
if (password_dialog->details->show_domain != show) {
password_dialog->details->show_domain = show;
add_table_rows (password_dialog);
}
}
void
gnome_two_password_dialog_set_show_password (GnomeTwoPasswordDialog *password_dialog,
gboolean show)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
show = !!show;
if (password_dialog->details->show_password != show) {
password_dialog->details->show_password = show;
add_table_rows (password_dialog);
}
}
void
gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *password_dialog,
gboolean show)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
show = !!show;
if (password_dialog->details->show_password_secondary != show) {
password_dialog->details->show_password_secondary = show;
add_table_rows (password_dialog);
}
}
void
gnome_two_password_dialog_set_readonly_username (GnomeTwoPasswordDialog *password_dialog,
gboolean readonly)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
password_dialog->details->readonly_username = readonly;
gtk_widget_set_sensitive (password_dialog->details->username_entry,
!readonly);
}
void
gnome_two_password_dialog_set_readonly_domain (GnomeTwoPasswordDialog *password_dialog,
gboolean readonly)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
password_dialog->details->readonly_domain = readonly;
gtk_widget_set_sensitive (password_dialog->details->domain_entry,
!readonly);
}
char *
gnome_two_password_dialog_get_username (GnomeTwoPasswordDialog *password_dialog)
{
g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->username_entry)));
}
char *
gnome_two_password_dialog_get_domain (GnomeTwoPasswordDialog *password_dialog)
{
g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->domain_entry)));
}
char *
gnome_two_password_dialog_get_password (GnomeTwoPasswordDialog *password_dialog)
{
g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->password_entry)));
}
char *
gnome_two_password_dialog_get_password_secondary (GnomeTwoPasswordDialog *password_dialog)
{
g_return_val_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog), NULL);
return g_strdup (gtk_entry_get_text (GTK_ENTRY (password_dialog->details->password_entry_secondary)));
}
void
gnome_two_password_dialog_set_show_userpass_buttons (GnomeTwoPasswordDialog *password_dialog,
gboolean show_userpass_buttons)
{
if (show_userpass_buttons) {
password_dialog->details->anon_support_on = TRUE;
gtk_widget_show (password_dialog->details->radio_vbox);
if (gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (password_dialog->details->connect_with_no_userpass_button))) {
gtk_widget_set_sensitive (password_dialog->details->table, FALSE);
}
else {
gtk_widget_set_sensitive (password_dialog->details->table, TRUE);
}
} else {
password_dialog->details->anon_support_on = FALSE;
gtk_widget_hide (password_dialog->details->radio_vbox);
gtk_widget_set_sensitive (password_dialog->details->table, TRUE);
}
add_table_rows (password_dialog);
}
gboolean
gnome_two_password_dialog_anon_selected (GnomeTwoPasswordDialog *password_dialog)
{
return password_dialog->details->anon_support_on &&
gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (
password_dialog->details->connect_with_no_userpass_button));
}
void
gnome_two_password_dialog_set_show_remember (GnomeTwoPasswordDialog *password_dialog,
gboolean show_remember)
{
if (show_remember) {
gtk_widget_show (password_dialog->details->remember_session_button);
gtk_widget_show (password_dialog->details->remember_forever_button);
} else {
gtk_widget_hide (password_dialog->details->remember_session_button);
gtk_widget_hide (password_dialog->details->remember_forever_button);
}
}
void
gnome_two_password_dialog_set_remember (GnomeTwoPasswordDialog *password_dialog,
GnomeTwoPasswordDialogRemember remember)
{
gboolean session, forever;
session = FALSE;
forever = FALSE;
if (remember == GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION) {
session = TRUE;
} else if (remember == GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER){
forever = TRUE;
}
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_session_button),
session);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_forever_button),
forever);
}
GnomeTwoPasswordDialogRemember
gnome_two_password_dialog_get_remember (GnomeTwoPasswordDialog *password_dialog)
{
gboolean session, forever;
session = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_session_button));
forever = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (password_dialog->details->remember_forever_button));
if (forever) {
return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER;
} else if (session) {
return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION;
}
return GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING;
}
void gnome_two_password_dialog_set_password_secondary_label (GnomeTwoPasswordDialog *password_dialog,
const char *password_secondary_label)
{
g_return_if_fail (password_dialog != NULL);
g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog));
g_free (password_dialog->details->secondary_password_label);
password_dialog->details->secondary_password_label = g_strdup (password_secondary_label);
if (password_dialog->details->show_password_secondary) {
add_table_rows (password_dialog);
}
}
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gnome-two-password-dialog.h - A use password prompting dialog widget
asking for two passwords. Based of
gnome-password-dialog.[ch] from libgnomeui
Copyright (C) 1999, 2000 Eazel, Inc.
Copyright (C) 2005, Red Hat, Inc.
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library 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
Library 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Authors: Ramiro Estrugo <ramiro@eazel.com>
*/
#ifndef GNOME_TWO_PASSWORD_DIALOG_H
#define GNOME_TWO_PASSWORD_DIALOG_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GNOME_TYPE_TWO_PASSWORD_DIALOG (gnome_two_password_dialog_get_type ())
#define GNOME_TWO_PASSWORD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_TWO_PASSWORD_DIALOG, GnomeTwoPasswordDialog))
#define GNOME_TWO_PASSWORD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_TWO_PASSWORD_DIALOG, GnomeTwoPasswordDialogClass))
#define GNOME_IS_TWO_PASSWORD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_TWO_PASSWORD_DIALOG))
#define GNOME_IS_TWO_PASSWORD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_TWO_PASSWORD_DIALOG))
typedef struct GnomeTwoPasswordDialog GnomeTwoPasswordDialog;
typedef struct GnomeTwoPasswordDialogClass GnomeTwoPasswordDialogClass;
typedef struct GnomeTwoPasswordDialogDetails GnomeTwoPasswordDialogDetails;
struct GnomeTwoPasswordDialog
{
GtkDialog gtk_dialog;
GnomeTwoPasswordDialogDetails *details;
};
struct GnomeTwoPasswordDialogClass
{
GtkDialogClass parent_class;
};
typedef enum {
GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING,
GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION,
GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER
} GnomeTwoPasswordDialogRemember;
GType gnome_two_password_dialog_get_type (void);
GtkWidget* gnome_two_password_dialog_new (const char *dialog_title,
const char *message,
const char *username,
const char *password,
gboolean readonly_username);
gboolean gnome_two_password_dialog_run_and_block (GnomeTwoPasswordDialog *password_dialog);
/* Attribute mutators */
void gnome_two_password_dialog_set_show_username (GnomeTwoPasswordDialog *password_dialog,
gboolean show);
void gnome_two_password_dialog_set_show_domain (GnomeTwoPasswordDialog *password_dialog,
gboolean show);
void gnome_two_password_dialog_set_show_password (GnomeTwoPasswordDialog *password_dialog,
gboolean show);
void gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *password_dialog,
gboolean show);
void gnome_two_password_dialog_set_username (GnomeTwoPasswordDialog *password_dialog,
const char *username);
void gnome_two_password_dialog_set_domain (GnomeTwoPasswordDialog *password_dialog,
const char *domain);
void gnome_two_password_dialog_set_password (GnomeTwoPasswordDialog *password_dialog,
const char *password);
void gnome_two_password_dialog_set_password_secondary (GnomeTwoPasswordDialog *password_dialog,
const char *password_secondary);
void gnome_two_password_dialog_set_readonly_username (GnomeTwoPasswordDialog *password_dialog,
gboolean readonly);
void gnome_two_password_dialog_set_readonly_domain (GnomeTwoPasswordDialog *password_dialog,
gboolean readonly);
void gnome_two_password_dialog_set_password_secondary_label (GnomeTwoPasswordDialog *password_dialog,
const char *password_secondary_description);
void gnome_two_password_dialog_set_show_remember (GnomeTwoPasswordDialog *password_dialog,
gboolean show_remember);
void gnome_two_password_dialog_set_remember (GnomeTwoPasswordDialog *password_dialog,
GnomeTwoPasswordDialogRemember remember);
GnomeTwoPasswordDialogRemember gnome_two_password_dialog_get_remember (GnomeTwoPasswordDialog *password_dialog);
void gnome_two_password_dialog_set_show_userpass_buttons (GnomeTwoPasswordDialog *password_dialog,
gboolean show_userpass_buttons);
/* Attribute accessors */
char * gnome_two_password_dialog_get_username (GnomeTwoPasswordDialog *password_dialog);
char * gnome_two_password_dialog_get_domain (GnomeTwoPasswordDialog *password_dialog);
char * gnome_two_password_dialog_get_password (GnomeTwoPasswordDialog *password_dialog);
char * gnome_two_password_dialog_get_password_secondary (GnomeTwoPasswordDialog *password_dialog);
gboolean gnome_two_password_dialog_anon_selected (GnomeTwoPasswordDialog *password_dialog);
G_END_DECLS
#endif /* GNOME_TWO_PASSWORD_DIALOG_H */
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Red Hat, Inc.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <nm-setting-vpn.h>
#include "src/nm-l2tp-service.h"
#include "common-gnome/keyring-helpers.h"
#include "gnome-two-password-dialog.h"
#define KEYRING_UUID_TAG "connection-uuid"
#define KEYRING_SN_TAG "setting-name"
#define KEYRING_SK_TAG "setting-key"
static gboolean
get_secrets (const char *vpn_uuid,
const char *vpn_name,
const char *vpn_service,
gboolean retry,
char **password)
{
GnomeTwoPasswordDialog *dialog;
gboolean is_session = TRUE;
char *prompt;
g_return_val_if_fail (vpn_uuid != NULL, FALSE);
g_return_val_if_fail (vpn_name != NULL, FALSE);
g_return_val_if_fail (password != NULL, FALSE);
g_return_val_if_fail (*password == NULL, FALSE);
*password = keyring_helpers_lookup_secret (vpn_uuid, NM_L2TP_KEY_PASSWORD, &is_session);
if (!retry && *password)
return TRUE;
prompt = g_strdup_printf (_("You need to authenticate to access the Virtual Private Network '%s'."), vpn_name);
dialog = GNOME_TWO_PASSWORD_DIALOG (gnome_two_password_dialog_new (_("Authenticate VPN"), prompt, NULL, NULL, FALSE));
g_free (prompt);
gnome_two_password_dialog_set_show_username (dialog, FALSE);
gnome_two_password_dialog_set_show_userpass_buttons (dialog, FALSE);
gnome_two_password_dialog_set_show_domain (dialog, FALSE);
gnome_two_password_dialog_set_show_remember (dialog, TRUE);
gnome_two_password_dialog_set_show_password_secondary (dialog, FALSE);
/* If nothing was found in the keyring, default to not remembering any secrets */
if (*password) {
/* Otherwise set default remember based on which keyring the secrets were found in */
if (is_session)
gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION);
else
gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER);
} else
gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING);
/* if retrying, pre-fill dialog with the password */
if (*password) {
gnome_two_password_dialog_set_password (dialog, *password);
g_free (*password);
*password = NULL;
}
gtk_widget_show (GTK_WIDGET (dialog));
if (gnome_two_password_dialog_run_and_block (dialog)) {
const char *keyring = NULL;
gboolean save = FALSE;
*password = gnome_two_password_dialog_get_password (dialog);
switch (gnome_two_password_dialog_get_remember (dialog)) {
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION:
keyring = "session";
/* Fall through */
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER:
save = TRUE;
break;
default:
break;
}
if (save) {
if (*password) {
keyring_helpers_save_secret (vpn_uuid, vpn_name, keyring,
NM_L2TP_KEY_PASSWORD, *password);
}
}
}
gtk_widget_hide (GTK_WIDGET (dialog));
gtk_widget_destroy (GTK_WIDGET (dialog));
return TRUE;
}
int
main (int argc, char *argv[])
{
gboolean retry = FALSE;
gchar *vpn_name = NULL;
gchar *vpn_uuid = NULL;
gchar *vpn_service = NULL;
char *password = NULL;
char buf[1];
int ret;
GOptionContext *context;
GOptionEntry entries[] = {
{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &vpn_uuid, "UUID of VPN connection", NULL},
{ "name", 'n', 0, G_OPTION_ARG_STRING, &vpn_name, "Name of VPN connection", NULL},
{ "service", 's', 0, G_OPTION_ARG_STRING, &vpn_service, "VPN service type", NULL},
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, NULL);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
gtk_init (&argc, &argv);
context = g_option_context_new ("- l2tp auth dialog");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
if (vpn_uuid == NULL || vpn_name == NULL || vpn_service == NULL) {
fprintf (stderr, "Have to supply UUID, name, and service\n");
return EXIT_FAILURE;
}
if (strcmp (vpn_service, NM_DBUS_SERVICE_L2TP) != 0) {
fprintf (stderr, "This dialog only works with the '%s' service\n", NM_DBUS_SERVICE_L2TP);
return EXIT_FAILURE;
}
if (!get_secrets (vpn_uuid, vpn_name, vpn_service, retry, &password))
return EXIT_FAILURE;
/* dump the passwords to stdout */
printf ("%s\n%s\n", NM_L2TP_KEY_PASSWORD, password);
printf ("\n\n");
if (password) {
memset (password, 0, strlen (password));
gnome_keyring_memory_free (password);
}
/* for good measure, flush stdout since Kansas is going Bye-Bye */
fflush (stdout);
/* wait for data on stdin */
ret = fread (buf, sizeof (char), sizeof (buf), stdin);
return EXIT_SUCCESS;
}
#!/bin/sh
autoreconf --verbose --install --force
intltoolize --copy --force --automake
noinst_LTLIBRARIES=libnm-l2tp-common-gnome.la
libnm_l2tp_common_gnome_la_CPPFLAGS = \
$(NM_UTILS_CFLAGS) \
$(GLIB_CFLAGS) \
$(GNOMEKEYRING_CFLAGS) \
-DG_DISABLE_DEPRECATED
libnm_l2tp_common_gnome_la_SOURCES= \
keyring-helpers.c \
keyring-helpers.h
libnm_l2tp_common_gnome_la_LIBADD = \
$(NM_UTILS_LIBS) \
$(GLIB_LIBS) \
$(GNOMEKEYRING_LIBS)
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2004 - 2008 Red Hat, Inc.
*/
#include <string.h>
#include <gnome-keyring-memory.h>
#include <nm-setting-vpn.h>
#include "keyring-helpers.h"
#include "../src/nm-l2tp-service.h"
#define KEYRING_UUID_TAG "connection-uuid"
#define KEYRING_SN_TAG "setting-name"
#define KEYRING_SK_TAG "setting-key"
char *
keyring_helpers_lookup_secret (const char *vpn_uuid,
const char *secret_name,
gboolean *is_session)
{
GList *found_list = NULL;
GnomeKeyringResult ret;
GnomeKeyringFound *found;
char *secret;
ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
&found_list,
KEYRING_UUID_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
vpn_uuid,
KEYRING_SN_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
NM_SETTING_VPN_SETTING_NAME,
KEYRING_SK_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
secret_name,
NULL);
if ((ret != GNOME_KEYRING_RESULT_OK) || (g_list_length (found_list) == 0))
return NULL;
found = (GnomeKeyringFound *) found_list->data;
if (is_session) {
if (strcmp (found->keyring, "session") == 0)
*is_session = TRUE;
else
*is_session = FALSE;
}
secret = found->secret ? gnome_keyring_memory_strdup (found->secret) : NULL;
gnome_keyring_found_list_free (found_list);
return secret;
}
GnomeKeyringResult
keyring_helpers_save_secret (const char *vpn_uuid,
const char *vpn_name,
const char *keyring,
const char *secret_name,
const char *secret)
{
char *display_name;
GnomeKeyringResult ret;
GnomeKeyringAttributeList *attrs = NULL;
guint32 id = 0;
display_name = g_strdup_printf ("VPN %s secret for %s/%s/" NM_SETTING_VPN_SETTING_NAME,
secret_name,
vpn_name,
NM_DBUS_SERVICE_L2TP);
attrs = gnome_keyring_attribute_list_new ();
gnome_keyring_attribute_list_append_string (attrs,
KEYRING_UUID_TAG,
vpn_uuid);
gnome_keyring_attribute_list_append_string (attrs,
KEYRING_SN_TAG,
NM_SETTING_VPN_SETTING_NAME);
gnome_keyring_attribute_list_append_string (attrs,
KEYRING_SK_TAG,
secret_name);
ret = gnome_keyring_item_create_sync (keyring,
GNOME_KEYRING_ITEM_GENERIC_SECRET,
display_name,
attrs,
secret,
TRUE,
&id);
gnome_keyring_attribute_list_free (attrs);
g_free (display_name);
return ret;
}
static void
ignore_callback (GnomeKeyringResult result, gpointer data)
{
}
gboolean
keyring_helpers_delete_secret (const char *vpn_uuid,
const char *secret_name)
{
GList *found = NULL, *iter;
GnomeKeyringResult ret;
g_return_val_if_fail (vpn_uuid != NULL, FALSE);
g_return_val_if_fail (secret_name != NULL, FALSE);
ret = gnome_keyring_find_itemsv_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
&found,
KEYRING_UUID_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
vpn_uuid,
KEYRING_SN_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
NM_SETTING_VPN_SETTING_NAME,
KEYRING_SK_TAG,
GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
secret_name,
NULL);
if (ret != GNOME_KEYRING_RESULT_OK && ret != GNOME_KEYRING_RESULT_NO_MATCH)
return FALSE;
if (g_list_length (found) == 0)
return TRUE;
/* delete them all */
for (iter = found; iter; iter = g_list_next (iter)) {
GnomeKeyringFound *item = (GnomeKeyringFound *) iter->data;
gnome_keyring_item_delete (item->keyring, item->item_id,
ignore_callback, NULL, NULL);
}
gnome_keyring_found_list_free (found);
return TRUE;
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2004 - 2008 Red Hat, Inc.
*/
#ifndef KEYRING_HELPERS_H
#define KEYRING_HELPERS_H
#include <glib.h>
#include <gnome-keyring.h>
#include <gnome-keyring-memory.h>
char *keyring_helpers_lookup_secret (
const char *vpn_uuid,
const char *secret_name,
gboolean *is_session);
GnomeKeyringResult keyring_helpers_save_secret (
const char *vpn_uuid,
const char *vpn_name,
const char *keyring,
const char *secret_name,
const char *secret);
gboolean keyring_helpers_delete_secret (
const char *vpn_uuid,
const char *secret_name);
#endif /* KEYRING_HELPERS_H */
AC_PREREQ(2.59)
AC_INIT(NetworkManager-l2tp, 0.8.1, dcbw@redhat.com, NetworkManager-l2tp)
AM_INIT_AUTOMAKE([1.9 foreign no-dist-gzip dist-bzip2 subdir-objects])
AM_MAINTAINER_MODE
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
dnl
dnl Require programs
dnl
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LIBTOOL
dnl
dnl Required headers
dnl
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h paths.h sys/ioctl.h sys/time.h syslog.h unistd.h)
AC_CHECK_HEADERS(pppd/pppd.h,,
AC_MSG_ERROR(couldn't find pppd.h. pppd development headers are required.))
AC_ARG_WITH([pppd-plugin-dir], AS_HELP_STRING([--with-pppd-plugin-dir=DIR], [path to the pppd plugins directory]))
if test -n "$with_pppd_plugin_dir" ; then
PPPD_PLUGIN_DIR="$with_pppd_plugin_dir"
else
PPPD_PLUGIN_DIR="${libdir}/pppd/2.4.4"
fi
AC_SUBST(PPPD_PLUGIN_DIR)
dnl
dnl Checks for typedefs, structures, and compiler characteristics.
dnl
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_HEADER_TIME
dnl
dnl Checks for library functions.
dnl
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_CHECK_FUNCS(select socket uname)
dnl
dnl GNOME support
dnl
AC_ARG_WITH(gnome, AS_HELP_STRING([--without-gnome], [Build NetworkManager-l2tp without GNOME support, e.g. vpn service only]))
AM_CONDITIONAL(WITH_GNOME, test x"$with_gnome" != xno)
GETTEXT_PACKAGE=NetworkManager-l2tp
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
IT_PROG_INTLTOOL([0.35])
AM_GLIB_GNU_GETTEXT
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
AC_SUBST(GTHREAD_CFLAGS)
AC_SUBST(GTHREAD_LIBS)
PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= 0.74)
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
PKG_CHECK_MODULES(NM_UTILS, NetworkManager >= 0.8.1 libnm-util libnm-glib libnm-glib-vpn)
AC_SUBST(NM_UTILS_CFLAGS)
AC_SUBST(NM_UTILS_LIBS)
if test x"$with_gnome" != xno; then
PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0)
AC_SUBST(GDK_PIXBUF_CFLAGS)
AC_SUBST(GDK_PIXBUF_LIBS)
PKG_CHECK_MODULES(GLADE, libglade-2.0)
AC_SUBST(GLADE_CFLAGS)
AC_SUBST(GLADE_LIBS)
PKG_CHECK_MODULES(GCONF, gconf-2.0)
AC_SUBST(GCONF_CFLAGS)
AC_SUBST(GCONF_LIBS)
PKG_CHECK_MODULES(GNOMEKEYRING, gnome-keyring-1)
AC_SUBST(GNOMEKEYRING_CFLAGS)
AC_SUBST(GNOMEKEYRING_LIBS)
fi
NM_COMPILER_WARNINGS
AC_CONFIG_FILES([
Makefile
src/Makefile
common-gnome/Makefile
auth-dialog/Makefile
properties/Makefile
po/Makefile.in
])
AC_OUTPUT
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.NetworkManager.l2tp"/>
<allow send_destination="org.freedesktop.NetworkManager.l2tp"/>
<allow own="org.freedesktop.NetworkManager.l2tp-ppp"/>
<allow send_destination="org.freedesktop.NetworkManager.l2tp-ppp"/>
</policy>
<policy context="default">
<deny own="org.freedesktop.NetworkManager.l2tp"/>
<deny send_destination="org.freedesktop.NetworkManager.l2tp"/>
<deny own="org.freedesktop.NetworkManager.l2tp-ppp"/>
<deny send_destination="org.freedesktop.NetworkManager.l2tp-ppp"/>
</policy>
</busconfig>
[VPN Connection]
name=l2tp
service=org.freedesktop.NetworkManager.l2tp
program=@LIBEXECDIR@/nm-l2tp-service
[GNOME]
auth-dialog=nm-l2tp-auth-dialog
properties=libnm-l2tp-properties
[Desktop Entry]
_Name=L2TP VPN Connection Manager
_GenericName=L2TP VPN Connection Manager
_Comment=Add, Remove, and Edit L2TP VPN Connections
Exec=nm-vpn-properties --import-service org.freedesktop.NetworkManager.l2tp --import-file %f
Icon=gnome-mime-application-x-l2tp-settings
Terminal=false
Type=Application
Categories=GNOME;Network;
MimeType=application/x-ppp-settings;
NoDisplay=true
# please keep this list sorted alphabetically
#
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
auth-dialog/gnome-two-password-dialog.c
auth-dialog/main.c
nm-l2tp.desktop.in
properties/nm-l2tp.c
properties/nm-l2tp-dialog.glade
src/nm-l2tp-service.c
plugindir = $(libdir)/NetworkManager
plugin_LTLIBRARIES = libnm-l2tp-properties.la
libnm_l2tp_properties_la_SOURCES = \
nm-l2tp.c \
nm-l2tp.h \
advanced-dialog.c \
advanced-dialog.h \
import-export.c \
import-export.h
gladedir = $(datadir)/gnome-vpn-properties/l2tp
glade_DATA = nm-l2tp-dialog.glade
libnm_l2tp_properties_la_CFLAGS = \
$(GLADE_CFLAGS) \
$(GTK_CFLAGS) \
$(GCONF_CFLAGS) \
$(LIBGNOMEUI_CFLAGS) \
$(GNOMEKEYRING_CFLAGS) \
$(NM_UTILS_CFLAGS) \
-DICONDIR=\""$(datadir)/pixmaps"\" \
-DGLADEDIR=\""$(gladedir)"\" \
-DG_DISABLE_DEPRECATED \
-DGDK_DISABLE_DEPRECATED \
-DGNOME_DISABLE_DEPRECATED \
-DGNOMELOCALEDIR=\"$(datadir)/locale\" \
-DVERSION=\"$(VERSION)\"
libnm_l2tp_properties_la_LIBADD = \
$(GLADE_LIBS) \
$(GTK_LIBS) \
$(GCONF_LIBS) \
$(LIBGNOMEUI_LIBS) \
$(top_builddir)/common-gnome/libnm-l2tp-common-gnome.la \
$(NM_UTILS_LIBS)
libnm_l2tp_properties_la_LDFLAGS = \
-avoid-version
CLEANFILES = *.bak *.gladep *~
EXTRA_DIST = \
$(glade_DATA)
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <glade/glade.h>
#include <nm-connection.h>
#include <nm-setting-vpn.h>
#include "advanced-dialog.h"
#include "nm-l2tp.h"
#include "../src/nm-l2tp-service.h"
#define COL_NAME 0
#define COL_VALUE 1
#define COL_TAG 2
#define COL_SENSITIVE 3
#define TAG_PAP 0
#define TAG_CHAP 1
#define TAG_MSCHAP 2
#define TAG_MSCHAPV2 3
#define TAG_EAP 4
static const char *advanced_keys[] = {
NM_L2TP_KEY_REFUSE_EAP,
NM_L2TP_KEY_REFUSE_PAP,
NM_L2TP_KEY_REFUSE_CHAP,
NM_L2TP_KEY_REFUSE_MSCHAP,
NM_L2TP_KEY_REFUSE_MSCHAPV2,
NM_L2TP_KEY_REQUIRE_MPPE,
NM_L2TP_KEY_REQUIRE_MPPE_40,
NM_L2TP_KEY_REQUIRE_MPPE_128,
NM_L2TP_KEY_MPPE_STATEFUL,
NM_L2TP_KEY_NOBSDCOMP,
NM_L2TP_KEY_NODEFLATE,
NM_L2TP_KEY_NO_VJ_COMP,
NM_L2TP_KEY_LCP_ECHO_FAILURE,
NM_L2TP_KEY_LCP_ECHO_INTERVAL,
NULL
};
static void
copy_values (const char *key, const char *value, gpointer user_data)
{
GHashTable *hash = (GHashTable *) user_data;
const char **i;
for (i = &advanced_keys[0]; *i; i++) {
if (strcmp (key, *i))
continue;
g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
}
}
GHashTable *
advanced_dialog_new_hash_from_connection (NMConnection *connection,
GError **error)
{
GHashTable *hash;
NMSettingVPN *s_vpn;
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
nm_setting_vpn_foreach_data_item (s_vpn, copy_values, hash);
return hash;
}
static void
handle_mppe_changed (GtkWidget *check, gboolean is_init, GladeXML *xml)
{
GtkWidget *widget;
gboolean use_mppe;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid;
use_mppe = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check));
/* At dialog-setup time, don't touch the auth methods if MPPE is disabled
* since that could overwrite the user's previously chosen auth methods.
* But ensure that at init time if MPPE is on that incompatible auth methods
* aren't selected.
*/
if (is_init && !use_mppe)
return;
/* If MPPE is active, PAP, CHAP, and EAP aren't allowed by the MPPE specs;
* likewise, if MPPE is inactive, sensitize the PAP, CHAP, and EAP checkboxes.
*/
widget = glade_xml_get_widget (xml, "ppp_auth_methods");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid) {
guint32 tag;
gtk_tree_model_get (model, &iter, COL_TAG, &tag, -1);
switch (tag) {
case TAG_PAP:
case TAG_CHAP:
case TAG_EAP:
gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_VALUE, !use_mppe, -1);
gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_SENSITIVE, !use_mppe, -1);
break;
default:
break;
}
valid = gtk_tree_model_iter_next (model, &iter);
}
widget = glade_xml_get_widget (xml, "ppp_mppe_security_label");
gtk_widget_set_sensitive (widget, use_mppe);
widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
if (!use_mppe)
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); /* default */
gtk_widget_set_sensitive (widget, use_mppe);
widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
if (!use_mppe)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
gtk_widget_set_sensitive (widget, use_mppe);
}
static void
mppe_toggled_cb (GtkWidget *check, gpointer user_data)
{
handle_mppe_changed (check, FALSE, (GladeXML *) user_data);
}
#define SEC_INDEX_DEFAULT 0
#define SEC_INDEX_MPPE_128 1
#define SEC_INDEX_MPPE_40 2
static void
setup_security_combo (GladeXML *xml, GHashTable *hash)
{
GtkWidget *widget;
GtkListStore *store;
GtkTreeIter iter;
int active = -1;
const char *value;
g_return_if_fail (xml != NULL);
g_return_if_fail (hash != NULL);
widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
store = gtk_list_store_new (1, G_TYPE_STRING);
/* Default (allow use of all encryption types that both server and client support) */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("All Available (Default)"), -1);
/* MPPE-128 */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("128-bit (most secure)"), -1);
if (active < 0) {
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_128);
if (value && !strcmp (value, "yes"))
active = SEC_INDEX_MPPE_128;
}
/* MPPE-40 */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("40-bit (less secure)"), -1);
if (active < 0) {
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_40);
if (value && !strcmp (value, "yes"))
active = SEC_INDEX_MPPE_40;
}
gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? SEC_INDEX_DEFAULT : active);
}
static void
check_toggled_cb (GtkCellRendererToggle *cell, gchar *path_str, gpointer user_data)
{
GladeXML *xml = GLADE_XML (user_data);
GtkWidget *widget;
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
GtkTreeModel *model;
GtkTreeIter iter;
gboolean toggle_item;
gboolean valid;
gboolean mschap_state = TRUE;
gboolean mschap2_state = TRUE;
widget = glade_xml_get_widget (xml, "ppp_auth_methods");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, COL_VALUE, &toggle_item, -1);
toggle_item ^= 1;
/* set new value */
gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_VALUE, toggle_item, -1);
gtk_tree_path_free (path);
/* If MSCHAP and MSCHAPv2 are both disabled, also disable MPPE */
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid) {
gboolean allowed;
guint32 tag;
gtk_tree_model_get (model, &iter, COL_VALUE, &allowed, COL_TAG, &tag, -1);
switch (tag) {
case TAG_MSCHAP:
mschap_state = allowed;
break;
case TAG_MSCHAPV2:
mschap2_state = allowed;
break;
default:
break;
}
valid = gtk_tree_model_iter_next (model, &iter);
}
widget = glade_xml_get_widget (xml, "ppp_use_mppe");
if (!mschap_state && !mschap2_state) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
gtk_widget_set_sensitive (widget, FALSE);
} else
gtk_widget_set_sensitive (widget, TRUE);
}
static void
auth_methods_setup (GladeXML *xml, GHashTable *hash)
{
GtkWidget *widget;
GtkListStore *store;
GtkTreeIter iter;
const char *value;
gboolean allowed;
gboolean use_mppe = FALSE;
GtkCellRendererToggle *check_renderer;
GtkCellRenderer *text_renderer;
GtkTreeViewColumn *column;
gint offset;
gboolean mschap_state = TRUE;
gboolean mschap2_state = TRUE;
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_BOOLEAN);
/* Check for MPPE */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE);
if (value && !strcmp (value, "yes"))
use_mppe = TRUE;
/* Or MPPE-128 */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_128);
if (value && !strcmp (value, "yes"))
use_mppe = TRUE;
/* Or MPPE-40 */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_40);
if (value && !strcmp (value, "yes"))
use_mppe = TRUE;
/* PAP */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REFUSE_PAP);
allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
if (use_mppe)
allowed = FALSE;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_NAME, _("PAP"),
COL_VALUE, allowed,
COL_TAG, TAG_PAP,
COL_SENSITIVE, !use_mppe,
-1);
/* CHAP */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REFUSE_CHAP);
allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
if (use_mppe)
allowed = FALSE;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_NAME, _("CHAP"),
COL_VALUE, allowed,
COL_TAG, TAG_CHAP,
COL_SENSITIVE, !use_mppe,
-1);
/* MSCHAP */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REFUSE_MSCHAP);
allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
mschap_state = allowed;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_NAME, _("MSCHAP"),
COL_VALUE, allowed,
COL_TAG, TAG_MSCHAP,
COL_SENSITIVE, TRUE,
-1);
/* MSCHAPv2 */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REFUSE_MSCHAPV2);
allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
mschap2_state = allowed;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_NAME, _("MSCHAPv2"),
COL_VALUE, allowed,
COL_TAG, TAG_MSCHAPV2,
COL_SENSITIVE, TRUE,
-1);
/* EAP */
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REFUSE_EAP);
allowed = (value && !strcmp (value, "yes")) ? FALSE : TRUE;
if (use_mppe)
allowed = FALSE;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_NAME, _("EAP"),
COL_VALUE, allowed,
COL_TAG, TAG_EAP,
COL_SENSITIVE, !use_mppe,
-1);
/* Set up the tree view */
widget = glade_xml_get_widget (xml, "ppp_auth_methods");
gtk_tree_view_set_model (GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store));
check_renderer = GTK_CELL_RENDERER_TOGGLE (gtk_cell_renderer_toggle_new ());
g_signal_connect (check_renderer, "toggled", G_CALLBACK (check_toggled_cb), xml);
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
-1, "", GTK_CELL_RENDERER (check_renderer),
"active", COL_VALUE,
"sensitive", COL_SENSITIVE,
"activatable", COL_SENSITIVE,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 30);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
text_renderer = gtk_cell_renderer_text_new ();
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
-1, "", text_renderer,
"text", COL_NAME,
"sensitive", COL_SENSITIVE,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
/* Make sure MPPE is non-sensitive if MSCHAP and MSCHAPv2 are disabled */
widget = glade_xml_get_widget (xml, "ppp_use_mppe");
if (!mschap_state && !mschap2_state) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
gtk_widget_set_sensitive (widget, FALSE);
} else
gtk_widget_set_sensitive (widget, TRUE);
}
GtkWidget *
advanced_dialog_new (GHashTable *hash)
{
GladeXML *xml;
GtkWidget *dialog = NULL;
char *glade_file = NULL;
GtkWidget *widget;
const char *value;
gboolean mppe = FALSE;
g_return_val_if_fail (hash != NULL, NULL);
glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-l2tp-dialog.glade");
xml = glade_xml_new (glade_file, "l2tp-advanced-dialog", GETTEXT_PACKAGE);
if (xml == NULL)
goto out;
dialog = glade_xml_get_widget (xml, "l2tp-advanced-dialog");
if (!dialog) {
g_object_unref (G_OBJECT (xml));
goto out;
}
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
g_object_set_data_full (G_OBJECT (dialog), "glade-xml",
xml, (GDestroyNotify) g_object_unref);
setup_security_combo (xml, hash);
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE);
if (value && !strcmp (value, "yes"))
mppe = TRUE;
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_40);
if (value && !strcmp (value, "yes"))
mppe = TRUE;
value = g_hash_table_lookup (hash, NM_L2TP_KEY_REQUIRE_MPPE_128);
if (value && !strcmp (value, "yes"))
mppe = TRUE;
widget = glade_xml_get_widget (xml, "ppp_use_mppe");
if (mppe)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
value = g_hash_table_lookup (hash, NM_L2TP_KEY_MPPE_STATEFUL);
if (value && !strcmp (value, "yes"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
widget = glade_xml_get_widget (xml, "ppp_allow_bsdcomp");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
value = g_hash_table_lookup (hash, NM_L2TP_KEY_NOBSDCOMP);
if (value && !strcmp (value, "yes"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
widget = glade_xml_get_widget (xml, "ppp_allow_deflate");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
value = g_hash_table_lookup (hash, NM_L2TP_KEY_NODEFLATE);
if (value && !strcmp (value, "yes"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
widget = glade_xml_get_widget (xml, "ppp_usevj");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
value = g_hash_table_lookup (hash, NM_L2TP_KEY_NO_VJ_COMP);
if (value && !strcmp (value, "yes"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
widget = glade_xml_get_widget (xml, "ppp_send_echo_packets");
value = g_hash_table_lookup (hash, NM_L2TP_KEY_LCP_ECHO_INTERVAL);
if (value && strlen (value)) {
long int tmp_int;
errno = 0;
tmp_int = strtol (value, NULL, 10);
if (errno == 0 && tmp_int > 0)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
}
auth_methods_setup (xml, hash);
widget = glade_xml_get_widget (xml, "ppp_use_mppe");
handle_mppe_changed (widget, TRUE, xml);
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (mppe_toggled_cb), xml);
out:
g_free (glade_file);
return dialog;
}
GHashTable *
advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error)
{
GHashTable *hash;
GtkWidget *widget;
GladeXML *xml;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid;
g_return_val_if_fail (dialog != NULL, NULL);
if (error)
g_return_val_if_fail (*error == NULL, NULL);
xml = g_object_get_data (G_OBJECT (dialog), "glade-xml");
g_return_val_if_fail (xml != NULL, NULL);
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
widget = glade_xml_get_widget (xml, "ppp_use_mppe");
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
widget = glade_xml_get_widget (xml, "ppp_mppe_security_combo");
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget))) {
case SEC_INDEX_MPPE_128:
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REQUIRE_MPPE_128), g_strdup ("yes"));
break;
case SEC_INDEX_MPPE_40:
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REQUIRE_MPPE_40), g_strdup ("yes"));
break;
default:
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REQUIRE_MPPE), g_strdup ("yes"));
break;
}
widget = glade_xml_get_widget (xml, "ppp_allow_stateful_mppe");
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_MPPE_STATEFUL), g_strdup ("yes"));
}
widget = glade_xml_get_widget (xml, "ppp_allow_bsdcomp");
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_NOBSDCOMP), g_strdup ("yes"));
widget = glade_xml_get_widget (xml, "ppp_allow_deflate");
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_NODEFLATE), g_strdup ("yes"));
widget = glade_xml_get_widget (xml, "ppp_usevj");
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_NO_VJ_COMP), g_strdup ("yes"));
widget = glade_xml_get_widget (xml, "ppp_send_echo_packets");
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_LCP_ECHO_FAILURE), g_strdup_printf ("%d", 5));
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_LCP_ECHO_INTERVAL), g_strdup_printf ("%d", 30));
}
widget = glade_xml_get_widget (xml, "ppp_auth_methods");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid) {
gboolean allowed;
guint32 tag;
gtk_tree_model_get (model, &iter, COL_VALUE, &allowed, COL_TAG, &tag, -1);
switch (tag) {
case TAG_PAP:
if (!allowed)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REFUSE_PAP), g_strdup ("yes"));
break;
case TAG_CHAP:
if (!allowed)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REFUSE_CHAP), g_strdup ("yes"));
break;
case TAG_MSCHAP:
if (!allowed)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REFUSE_MSCHAP), g_strdup ("yes"));
break;
case TAG_MSCHAPV2:
if (!allowed)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REFUSE_MSCHAPV2), g_strdup ("yes"));
break;
case TAG_EAP:
if (!allowed)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_REFUSE_EAP), g_strdup ("yes"));
break;
default:
break;
}
valid = gtk_tree_model_iter_next (model, &iter);
}
return hash;
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifndef _AUTH_HELPERS_H_
#define _AUTH_HELPERS_H_
#include <glib.h>
#include <gtk/gtk.h>
#include <nm-connection.h>
GtkWidget *advanced_dialog_new (GHashTable *hash);
GHashTable *advanced_dialog_new_hash_from_connection (NMConnection *connection, GError **error);
GHashTable *advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error);
#endif
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <glib/gi18n-lib.h>
#include <nm-setting-vpn.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#include "import-export.h"
#include "nm-l2tp.h"
#include "../src/nm-l2tp-service.h"
NMConnection *
do_import (const char *path, char **lines, GError **error)
{
return NULL;
}
gboolean
do_export (const char *path, NMConnection *connection, GError **error)
{
return FALSE;
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifndef _IMPORT_EXPORT_H_
#define _IMPORT_EXPORT_H_
#include <glib.h>
#include <nm-connection.h>
NMConnection *do_import (const char *path, char **lines, GError **error);
gboolean do_export (const char *path, NMConnection *connection, GError **error);
#endif
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.4 on Sun Oct 12 10:59:11 2008 -->
<glade-interface>
<widget class="GtkWindow" id="l2tp-widget">
<property name="title" translatable="yes">window1</property>
<child>
<widget class="GtkVBox" id="l2tp-vbox">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">16</property>
<child>
<widget class="GtkVBox" id="vbox8">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment8">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_columns">2</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkEntry" id="gateway_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Gateway:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">gateway_entry</property>
</widget>
<packing>
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox11">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label25">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Optional&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment9">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkEntry" id="domain_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label27">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">NT Domain:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="show_passwords_checkbutton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show password</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="user_password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Password:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="user_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label26">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">User name:</property>
</widget>
<packing>
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xscale">0</property>
<child>
<widget class="GtkButton" id="advanced_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="response_id">0</property>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-preferences</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Ad_vanced...</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">GTK_PACK_END</property>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="l2tp-advanced-dialog">
<property name="border_width">5</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="title" translatable="yes">L2TP Advanced Options</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">stock-preferences</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="skip_pager_hint">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox3">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkVBox" id="PppPage">
<property name="visible">True</property>
<property name="border_width">5</property>
<property name="spacing">18</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label28">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Authentication&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="auth_methods_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Allow the following authentication methods:</property>
</widget>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkTreeView" id="ppp_auth_methods">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label29">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Security and Compression&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox6">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkVBox" id="vbox7">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkCheckButton" id="ppp_use_mppe">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Use _Point-to-Point encryption (MPPE)</property>
<property name="tooltip" translatable="yes">Note: MPPE encryption is only available with MSCHAP authentication methods. To enable this checkbox, select one or more of the MSCHAP authentication methods: MSCHAP or MSCHAPv2.</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">12</property>
<child>
<widget class="GtkLabel" id="ppp_mppe_security_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Security:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">ppp_mppe_security_combo</property>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="ppp_mppe_security_combo">
<property name="visible">True</property>
<property name="items" translatable="yes">Default</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkCheckButton" id="ppp_allow_stateful_mppe">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Allow st_ateful encryption</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="ppp_allow_bsdcomp">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Allow _BSD data compression</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="ppp_allow_deflate">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Allow _Deflate data compression</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="ppp_usevj">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Use TCP _header compression</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox9">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label31">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Echo&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkCheckButton" id="ppp_send_echo_packets">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Send PPP _echo packets</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area3">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="cancel_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="ok_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">-5</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
* nm-l2tp.c : GNOME UI dialogs for configuring L2TP VPN connections
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
* Based on work by David Zeuthen, <davidz@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <glib/gi18n-lib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#define NM_VPN_API_SUBJECT_TO_CHANGE
#include <nm-vpn-plugin-ui-interface.h>
#include <nm-setting-vpn.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#include "../src/nm-l2tp-service.h"
#include "../common-gnome/keyring-helpers.h"
#include "nm-l2tp.h"
#include "import-export.h"
#include "advanced-dialog.h"
#define L2TP_PLUGIN_NAME _("Point-to-Point Tunneling Protocol (L2TP)")
#define L2TP_PLUGIN_DESC _("Compatible with Microsoft and other L2TP VPN servers.")
#define L2TP_PLUGIN_SERVICE NM_DBUS_SERVICE_L2TP
typedef void (*ChangedCallback) (GtkWidget *widget, gpointer user_data);
/************** plugin class **************/
static void l2tp_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class);
G_DEFINE_TYPE_EXTENDED (L2tpPluginUi, l2tp_plugin_ui, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_INTERFACE,
l2tp_plugin_ui_interface_init))
/************** UI widget class **************/
static void l2tp_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class);
G_DEFINE_TYPE_EXTENDED (L2tpPluginUiWidget, l2tp_plugin_ui_widget, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_WIDGET_INTERFACE,
l2tp_plugin_ui_widget_interface_init))
#define L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), L2TP_TYPE_PLUGIN_UI_WIDGET, L2tpPluginUiWidgetPrivate))
typedef struct {
GladeXML *xml;
GtkWidget *widget;
GtkSizeGroup *group;
GtkWindowGroup *window_group;
gboolean window_added;
GHashTable *advanced;
} L2tpPluginUiWidgetPrivate;
GQuark
l2tp_plugin_ui_error_quark (void)
{
static GQuark error_quark = 0;
if (G_UNLIKELY (error_quark == 0))
error_quark = g_quark_from_static_string ("l2tp-plugin-ui-error-quark");
return error_quark;
}
/* This should really be standard. */
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
GType
l2tp_plugin_ui_error_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
/* Unknown error. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_UNKNOWN, "UnknownError"),
/* The connection was missing invalid. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_INVALID_CONNECTION, "InvalidConnection"),
/* The specified property was invalid. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_INVALID_PROPERTY, "InvalidProperty"),
/* The specified property was missing and is required. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_MISSING_PROPERTY, "MissingProperty"),
/* The file to import could not be read. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_FILE_NOT_READABLE, "FileNotReadable"),
/* The file to import could was not an L2TP client file. */
ENUM_ENTRY (L2TP_PLUGIN_UI_ERROR_FILE_NOT_L2TP, "FileNotL2TP"),
{ 0, 0, 0 }
};
etype = g_enum_register_static ("L2tpPluginUiError", values);
}
return etype;
}
static gboolean
check_validity (L2tpPluginUiWidget *self, GError **error)
{
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
GtkWidget *widget;
const char *str;
widget = glade_xml_get_widget (priv->xml, "gateway_entry");
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (!str || !strlen (str)) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_INVALID_PROPERTY,
NM_L2TP_KEY_GATEWAY);
return FALSE;
}
return TRUE;
}
static void
stuff_changed_cb (GtkWidget *widget, gpointer user_data)
{
g_signal_emit_by_name (L2TP_PLUGIN_UI_WIDGET (user_data), "changed");
}
static void
advanced_dialog_close_cb (GtkWidget *dialog, gpointer user_data)
{
gtk_widget_hide (dialog);
/* gtk_widget_destroy() will remove the window from the window group */
gtk_widget_destroy (dialog);
}
static void
advanced_dialog_response_cb (GtkWidget *dialog, gint response, gpointer user_data)
{
L2tpPluginUiWidget *self = L2TP_PLUGIN_UI_WIDGET (user_data);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
GError *error = NULL;
if (response != GTK_RESPONSE_OK) {
advanced_dialog_close_cb (dialog, self);
return;
}
if (priv->advanced)
g_hash_table_destroy (priv->advanced);
priv->advanced = advanced_dialog_new_hash_from_dialog (dialog, &error);
if (!priv->advanced) {
g_message ("%s: error reading advanced settings: %s", __func__, error->message);
g_error_free (error);
}
advanced_dialog_close_cb (dialog, self);
stuff_changed_cb (NULL, self);
}
static void
advanced_button_clicked_cb (GtkWidget *button, gpointer user_data)
{
L2tpPluginUiWidget *self = L2TP_PLUGIN_UI_WIDGET (user_data);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
GtkWidget *dialog, *toplevel;
toplevel = gtk_widget_get_toplevel (priv->widget);
g_return_if_fail (GTK_WIDGET_TOPLEVEL (toplevel));
dialog = advanced_dialog_new (priv->advanced);
if (!dialog) {
g_warning ("%s: failed to create the Advanced dialog!", __func__);
return;
}
gtk_window_group_add_window (priv->window_group, GTK_WINDOW (dialog));
if (!priv->window_added) {
gtk_window_group_add_window (priv->window_group, GTK_WINDOW (toplevel));
priv->window_added = TRUE;
}
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (advanced_dialog_response_cb), self);
g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (advanced_dialog_close_cb), self);
gtk_widget_show_all (dialog);
}
static void
show_toggled_cb (GtkCheckButton *button, L2tpPluginUiWidget *self)
{
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
GtkWidget *widget;
gboolean visible;
visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
widget = glade_xml_get_widget (priv->xml, "user_password_entry");
g_assert (widget);
gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
}
static GtkWidget *
fill_password (GladeXML *xml,
const char *widget_name,
NMConnection *connection,
const char *password_type)
{
GtkWidget *widget = NULL;
gchar *password = NULL;
widget = glade_xml_get_widget (xml, widget_name);
g_assert (widget);
if (!connection)
return widget;
password = NULL;
if (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) {
NMSettingVPN *s_vpn;
s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
if (s_vpn) {
const gchar *tmp = NULL;
tmp = nm_setting_vpn_get_secret (s_vpn, password_type);
if (tmp)
password = gnome_keyring_memory_strdup (tmp);
}
} else {
NMSettingConnection *s_con = NULL;
gboolean unused;
const char *uuid;
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
uuid = nm_setting_connection_get_uuid (s_con);
password = keyring_helpers_lookup_secret (uuid,
password_type,
&unused);
}
if (password) {
gtk_entry_set_text (GTK_ENTRY (widget), password);
gnome_keyring_memory_free (password);
}
return widget;
}
static void
fill_vpn_passwords (GladeXML *xml,
GtkSizeGroup *group,
NMConnection *connection,
ChangedCallback changed_cb,
gpointer user_data)
{
GtkWidget *w = NULL;
w = fill_password (xml, "user_password_entry", connection, NM_L2TP_KEY_PASSWORD);
if (w) {
gtk_size_group_add_widget (group, w);
g_signal_connect (w, "changed", G_CALLBACK (changed_cb), user_data);
} else {
g_error ("No user_password_entry in glade file!");
}
}
static gboolean
init_plugin_ui (L2tpPluginUiWidget *self, NMConnection *connection, GError **error)
{
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
NMSettingVPN *s_vpn;
GtkWidget *widget;
const char *value;
s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
widget = glade_xml_get_widget (priv->xml, "gateway_entry");
if (!widget)
return FALSE;
gtk_size_group_add_widget (priv->group, widget);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_GATEWAY);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
widget = glade_xml_get_widget (priv->xml, "user_entry");
if (!widget)
return FALSE;
gtk_size_group_add_widget (priv->group, widget);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_USER);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
widget = glade_xml_get_widget (priv->xml, "domain_entry");
if (!widget)
return FALSE;
gtk_size_group_add_widget (priv->group, widget);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_DOMAIN);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
widget = glade_xml_get_widget (priv->xml, "advanced_button");
g_signal_connect (G_OBJECT (widget), "clicked", G_CALLBACK (advanced_button_clicked_cb), self);
widget = glade_xml_get_widget (priv->xml, "show_passwords_checkbutton");
g_return_val_if_fail (widget != NULL, FALSE);
g_signal_connect (G_OBJECT (widget), "toggled",
(GCallback) show_toggled_cb,
self);
fill_vpn_passwords (priv->xml, priv->group, connection, stuff_changed_cb, self);
return TRUE;
}
static GObject *
get_widget (NMVpnPluginUiWidgetInterface *iface)
{
L2tpPluginUiWidget *self = L2TP_PLUGIN_UI_WIDGET (iface);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
return G_OBJECT (priv->widget);
}
static void
hash_copy_advanced (gpointer key, gpointer data, gpointer user_data)
{
NMSettingVPN *s_vpn = NM_SETTING_VPN (user_data);
nm_setting_vpn_add_data_item (s_vpn, (const char *) key, (const char *) data);
}
static gboolean
update_connection (NMVpnPluginUiWidgetInterface *iface,
NMConnection *connection,
GError **error)
{
L2tpPluginUiWidget *self = L2TP_PLUGIN_UI_WIDGET (iface);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
NMSettingVPN *s_vpn;
GtkWidget *widget;
const char *str;
gboolean valid = FALSE;
if (!check_validity (self, error))
return FALSE;
s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, NM_DBUS_SERVICE_L2TP, NULL);
/* Gateway */
widget = glade_xml_get_widget (priv->xml, "gateway_entry");
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_L2TP_KEY_GATEWAY, str);
/* Username */
widget = glade_xml_get_widget (priv->xml, "user_entry");
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_L2TP_KEY_USER, str);
/* Domain */
widget = glade_xml_get_widget (priv->xml, "domain_entry");
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_L2TP_KEY_DOMAIN, str);
if (priv->advanced)
g_hash_table_foreach (priv->advanced, hash_copy_advanced, s_vpn);
nm_connection_add_setting (connection, NM_SETTING (s_vpn));
valid = TRUE;
return valid;
}
static gboolean
save_secrets (NMVpnPluginUiWidgetInterface *iface,
NMConnection *connection,
GError **error)
{
L2tpPluginUiWidget *self = L2TP_PLUGIN_UI_WIDGET (iface);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
GnomeKeyringResult ret;
NMSettingConnection *s_con;
GtkWidget *widget;
const char *str, *uuid, *id;
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
if (!s_con) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
"missing 'connection' setting");
return FALSE;
}
id = nm_setting_connection_get_id (s_con);
uuid = nm_setting_connection_get_uuid (s_con);
widget = glade_xml_get_widget (priv->xml, "user_password_entry");
g_assert (widget);
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str)) {
ret = keyring_helpers_save_secret (uuid, id, NULL, NM_L2TP_KEY_PASSWORD, str);
if (ret != GNOME_KEYRING_RESULT_OK)
g_warning ("%s: failed to save user password to keyring.", __func__);
} else
keyring_helpers_delete_secret (uuid, NM_L2TP_KEY_PASSWORD);
return TRUE;
}
static NMVpnPluginUiWidgetInterface *
nm_vpn_plugin_ui_widget_interface_new (NMConnection *connection, GError **error)
{
NMVpnPluginUiWidgetInterface *object;
L2tpPluginUiWidgetPrivate *priv;
char *glade_file;
if (error)
g_return_val_if_fail (*error == NULL, NULL);
object = NM_VPN_PLUGIN_UI_WIDGET_INTERFACE (g_object_new (L2TP_TYPE_PLUGIN_UI_WIDGET, NULL));
if (!object) {
g_set_error (error, L2TP_PLUGIN_UI_ERROR, 0, "could not create l2tp object");
return NULL;
}
priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (object);
glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-l2tp-dialog.glade");
priv->xml = glade_xml_new (glade_file, "l2tp-vbox", GETTEXT_PACKAGE);
if (priv->xml == NULL) {
g_set_error (error, L2TP_PLUGIN_UI_ERROR, 0,
"could not load required resources at %s", glade_file);
g_free (glade_file);
g_object_unref (object);
return NULL;
}
g_free (glade_file);
priv->widget = glade_xml_get_widget (priv->xml, "l2tp-vbox");
if (!priv->widget) {
g_set_error (error, L2TP_PLUGIN_UI_ERROR, 0, "could not load UI widget");
g_object_unref (object);
return NULL;
}
g_object_ref_sink (priv->widget);
priv->window_group = gtk_window_group_new ();
if (!init_plugin_ui (L2TP_PLUGIN_UI_WIDGET (object), connection, error)) {
g_object_unref (object);
return NULL;
}
priv->advanced = advanced_dialog_new_hash_from_connection (connection, error);
if (!priv->advanced) {
g_object_unref (object);
return NULL;
}
return object;
}
static void
dispose (GObject *object)
{
L2tpPluginUiWidget *plugin = L2TP_PLUGIN_UI_WIDGET (object);
L2tpPluginUiWidgetPrivate *priv = L2TP_PLUGIN_UI_WIDGET_GET_PRIVATE (plugin);
if (priv->group)
g_object_unref (priv->group);
if (priv->window_group)
g_object_unref (priv->window_group);
if (priv->widget)
g_object_unref (priv->widget);
if (priv->xml)
g_object_unref (priv->xml);
if (priv->advanced)
g_hash_table_destroy (priv->advanced);
G_OBJECT_CLASS (l2tp_plugin_ui_widget_parent_class)->dispose (object);
}
static void
l2tp_plugin_ui_widget_class_init (L2tpPluginUiWidgetClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
g_type_class_add_private (req_class, sizeof (L2tpPluginUiWidgetPrivate));
object_class->dispose = dispose;
}
static void
l2tp_plugin_ui_widget_init (L2tpPluginUiWidget *plugin)
{
}
static void
l2tp_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class)
{
/* interface implementation */
iface_class->get_widget = get_widget;
iface_class->update_connection = update_connection;
iface_class->save_secrets = save_secrets;
}
static gboolean
delete_connection (NMVpnPluginUiInterface *iface,
NMConnection *connection,
GError **error)
{
NMSettingConnection *s_con = NULL;
const char *uuid;
/* Remove any secrets in the keyring associated with this connection's UUID */
s_con = (NMSettingConnection *) nm_connection_get_setting (connection,
NM_TYPE_SETTING_CONNECTION);
if (!s_con) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
"missing 'connection' setting");
return FALSE;
}
uuid = nm_setting_connection_get_uuid (s_con);
keyring_helpers_delete_secret (uuid, NM_L2TP_KEY_PASSWORD);
return TRUE;
}
static NMConnection *
import (NMVpnPluginUiInterface *iface, const char *path, GError **error)
{
NMConnection *connection = NULL;
char *contents = NULL;
char **lines = NULL;
char *ext;
ext = strrchr (path, '.');
if (!ext) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_FILE_NOT_L2TP,
"unknown L2TP file extension");
goto out;
}
if (strcmp (ext, ".conf") && strcmp (ext, ".cnf")) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_FILE_NOT_L2TP,
"unknown L2TP file extension");
goto out;
}
if (!g_file_get_contents (path, &contents, NULL, error))
return NULL;
lines = g_strsplit_set (contents, "\r\n", 0);
if (g_strv_length (lines) <= 1) {
g_set_error (error,
L2TP_PLUGIN_UI_ERROR,
L2TP_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
"not a valid L2TP configuration file");
goto out;
}
connection = do_import (path, lines, error);
out:
if (lines)
g_strfreev (lines);
g_free (contents);
return connection;
}
static gboolean
export (NMVpnPluginUiInterface *iface,
const char *path,
NMConnection *connection,
GError **error)
{
return do_export (path, connection, error);
}
static char *
get_suggested_name (NMVpnPluginUiInterface *iface, NMConnection *connection)
{
NMSettingConnection *s_con;
const char *id;
g_return_val_if_fail (connection != NULL, NULL);
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
g_return_val_if_fail (s_con != NULL, NULL);
id = nm_setting_connection_get_id (s_con);
g_return_val_if_fail (id != NULL, NULL);
return g_strdup_printf ("%s (l2tp).conf", id);
}
static guint32
get_capabilities (NMVpnPluginUiInterface *iface)
{
return (NM_VPN_PLUGIN_UI_CAPABILITY_IMPORT | NM_VPN_PLUGIN_UI_CAPABILITY_EXPORT);
}
static NMVpnPluginUiWidgetInterface *
ui_factory (NMVpnPluginUiInterface *iface, NMConnection *connection, GError **error)
{
return nm_vpn_plugin_ui_widget_interface_new (connection, error);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME:
g_value_set_string (value, L2TP_PLUGIN_NAME);
break;
case NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC:
g_value_set_string (value, L2TP_PLUGIN_DESC);
break;
case NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE:
g_value_set_string (value, L2TP_PLUGIN_SERVICE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
l2tp_plugin_ui_class_init (L2tpPluginUiClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
object_class->get_property = get_property;
g_object_class_override_property (object_class,
NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME,
NM_VPN_PLUGIN_UI_INTERFACE_NAME);
g_object_class_override_property (object_class,
NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
NM_VPN_PLUGIN_UI_INTERFACE_DESC);
g_object_class_override_property (object_class,
NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE,
NM_VPN_PLUGIN_UI_INTERFACE_SERVICE);
}
static void
l2tp_plugin_ui_init (L2tpPluginUi *plugin)
{
}
static void
l2tp_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class)
{
/* interface implementation */
iface_class->ui_factory = ui_factory;
iface_class->get_capabilities = get_capabilities;
iface_class->import_from_file = import;
iface_class->export_to_file = export;
iface_class->get_suggested_name = get_suggested_name;
iface_class->delete_connection = delete_connection;
}
G_MODULE_EXPORT NMVpnPluginUiInterface *
nm_vpn_plugin_ui_factory (GError **error)
{
if (error)
g_return_val_if_fail (*error == NULL, NULL);
return NM_VPN_PLUGIN_UI_INTERFACE (g_object_new (L2TP_TYPE_PLUGIN_UI, NULL));
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
* nm-l2tp.h : GNOME UI dialogs for configuring l2tp VPN connections
*
* Copyright (C) 2008 Dan Williams, <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#ifndef _NM_L2TP_H_
#define _NM_L2TP_H_
#include <glib-object.h>
typedef enum
{
L2TP_PLUGIN_UI_ERROR_UNKNOWN = 0,
L2TP_PLUGIN_UI_ERROR_INVALID_CONNECTION,
L2TP_PLUGIN_UI_ERROR_INVALID_PROPERTY,
L2TP_PLUGIN_UI_ERROR_MISSING_PROPERTY,
L2TP_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
L2TP_PLUGIN_UI_ERROR_FILE_NOT_L2TP
} L2tpPluginUiError;
#define L2TP_TYPE_PLUGIN_UI_ERROR (l2tp_plugin_ui_error_get_type ())
GType l2tp_plugin_ui_error_get_type (void);
#define L2TP_PLUGIN_UI_ERROR (l2tp_plugin_ui_error_quark ())
GQuark l2tp_plugin_ui_error_quark (void);
#define L2TP_TYPE_PLUGIN_UI (l2tp_plugin_ui_get_type ())
#define L2TP_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), L2TP_TYPE_PLUGIN_UI, L2tpPluginUi))
#define L2TP_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), L2TP_TYPE_PLUGIN_UI, L2tpPluginUiClass))
#define L2TP_IS_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), L2TP_TYPE_PLUGIN_UI))
#define L2TP_IS_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), L2TP_TYPE_PLUGIN_UI))
#define L2TP_PLUGIN_UI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), L2TP_TYPE_PLUGIN_UI, L2tpPluginUiClass))
typedef struct _L2tpPluginUi L2tpPluginUi;
typedef struct _L2tpPluginUiClass L2tpPluginUiClass;
struct _L2tpPluginUi {
GObject parent;
};
struct _L2tpPluginUiClass {
GObjectClass parent;
};
GType l2tp_plugin_ui_get_type (void);
#define L2TP_TYPE_PLUGIN_UI_WIDGET (l2tp_plugin_ui_widget_get_type ())
#define L2TP_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), L2TP_TYPE_PLUGIN_UI_WIDGET, L2tpPluginUiWidget))
#define L2TP_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), L2TP_TYPE_PLUGIN_UI_WIDGET, L2tpPluginUiWidgetClass))
#define L2TP_IS_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), L2TP_TYPE_PLUGIN_UI_WIDGET))
#define L2TP_IS_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), L2TP_TYPE_PLUGIN_UI_WIDGET))
#define L2TP_PLUGIN_UI_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), L2TP_TYPE_PLUGIN_UI_WIDGET, L2tpPluginUiWidgetClass))
typedef struct _L2tpPluginUiWidget L2tpPluginUiWidget;
typedef struct _L2tpPluginUiWidgetClass L2tpPluginUiWidgetClass;
struct _L2tpPluginUiWidget {
GObject parent;
};
struct _L2tpPluginUiWidgetClass {
GObjectClass parent;
};
GType l2tp_plugin_ui_widget_get_type (void);
#endif /* _NM_L2TP_H_ */
INCLUDES = -I${top_srcdir}
AM_CPPFLAGS = \
$(DBUS_GLIB_CFLAGS) \
$(GTHREAD_CFLAGS) \
$(NM_UTILS_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DBINDIR=\"$(bindir)\" \
-DPREFIX=\""$(prefix)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DNM_VERSION="\"$(VERSION)\"" \
-DLIBDIR=\""$(libdir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DLOCALSTATEDIR=\""$(localstatedir)"\" \
-DDATADIR=\"$(datadir)\" \
-DPLUGINDIR=\"$(PPPD_PLUGIN_DIR)\"
libexec_PROGRAMS = nm-l2tp-service
nm_l2tp_service_SOURCES = \
nm-l2tp-service.c \
nm-l2tp-service.h
nm-l2tp-pppd-service-glue.h: $(top_srcdir)/src/nm-l2tp-pppd-service.xml
dbus-binding-tool --prefix=nm_l2tp_pppd_service --mode=glib-server --output=$@ $<
nm_l2tp_service_LDADD = \
$(DBUS_GLIB_LIBS) \
$(GTHREAD_LIBS) \
$(NM_UTILS_LIBS)
pppd_plugindir = $(PPPD_PLUGIN_DIR)
pppd_plugin_LTLIBRARIES = nm-l2tp-pppd-plugin.la
nm_l2tp_pppd_plugin_la_SOURCES = \
nm-l2tp-pppd-plugin.c \
nm-ppp-status.h
nm_l2tp_pppd_plugin_la_CPPFLAGS = \
$(DBUS_GLIB_CFLAGS) \
$(GLIB_CFLAGS) \
$(NM_UTILS_CFLAGS)
nm_l2tp_pppd_plugin_la_LDFLAGS = -module -avoid-version
nm_l2tp_pppd_plugin_la_LIBADD = \
$(DBUS_GLIB_LIBS) \
$(GLIB_LIBS) \
$(NM_UTILS_LIBS)
BUILT_SOURCES = nm-l2tp-pppd-service-glue.h
CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = nm-l2tp-pppd-service.xml
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-l2tp-service - l2tp (and other pppd) integration with NetworkManager
*
* (C) 2007 - 2008 Novell, Inc.
* (C) 2008 - 2009 Red Hat, Inc.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*
*/
#include <string.h>
#include <pppd/pppd.h>
#include <pppd/fsm.h>
#include <pppd/ipcp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>
#include "nm-l2tp-service.h"
#include "nm-ppp-status.h"
#include <nm-utils.h>
int plugin_init (void);
char pppd_version[] = VERSION;
static DBusGProxy *proxy = NULL;
static void
nm_phasechange (void *data, int arg)
{
NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN;
char *ppp_phase;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
switch (arg) {
case PHASE_DEAD:
ppp_status = NM_PPP_STATUS_DEAD;
ppp_phase = "dead";
break;
case PHASE_INITIALIZE:
ppp_status = NM_PPP_STATUS_INITIALIZE;
ppp_phase = "initialize";
break;
case PHASE_SERIALCONN:
ppp_status = NM_PPP_STATUS_SERIALCONN;
ppp_phase = "serial connection";
break;
case PHASE_DORMANT:
ppp_status = NM_PPP_STATUS_DORMANT;
ppp_phase = "dormant";
break;
case PHASE_ESTABLISH:
ppp_status = NM_PPP_STATUS_ESTABLISH;
ppp_phase = "establish";
break;
case PHASE_AUTHENTICATE:
ppp_status = NM_PPP_STATUS_AUTHENTICATE;
ppp_phase = "authenticate";
break;
case PHASE_CALLBACK:
ppp_status = NM_PPP_STATUS_CALLBACK;
ppp_phase = "callback";
break;
case PHASE_NETWORK:
ppp_status = NM_PPP_STATUS_NETWORK;
ppp_phase = "network";
break;
case PHASE_RUNNING:
ppp_status = NM_PPP_STATUS_RUNNING;
ppp_phase = "running";
break;
case PHASE_TERMINATE:
ppp_status = NM_PPP_STATUS_TERMINATE;
ppp_phase = "terminate";
break;
case PHASE_DISCONNECT:
ppp_status = NM_PPP_STATUS_DISCONNECT;
ppp_phase = "disconnect";
break;
case PHASE_HOLDOFF:
ppp_status = NM_PPP_STATUS_HOLDOFF;
ppp_phase = "holdoff";
break;
case PHASE_MASTER:
ppp_status = NM_PPP_STATUS_MASTER;
ppp_phase = "master";
break;
default:
ppp_phase = "unknown";
break;
}
g_message ("nm-l2tp-ppp-plugin: (%s): status %d / phase '%s'",
__func__,
ppp_status,
ppp_phase);
if (ppp_status != NM_PPP_STATUS_UNKNOWN) {
dbus_g_proxy_call_no_reply (proxy, "SetState",
G_TYPE_UINT, ppp_status,
G_TYPE_INVALID,
G_TYPE_INVALID);
}
}
static GValue *
str_to_gvalue (const char *str)
{
GValue *val;
val = g_slice_new0 (GValue);
g_value_init (val, G_TYPE_STRING);
g_value_set_string (val, str);
return val;
}
static GValue *
uint_to_gvalue (guint32 i)
{
GValue *val;
val = g_slice_new0 (GValue);
g_value_init (val, G_TYPE_UINT);
g_value_set_uint (val, i);
return val;
}
static void
value_destroy (gpointer data)
{
GValue *val = (GValue *) data;
g_value_unset (val);
g_slice_free (GValue, val);
}
static void
nm_ip_up (void *data, int arg)
{
guint32 pppd_made_up_address = htonl (0x0a404040 + ifunit);
ipcp_options opts = ipcp_gotoptions[0];
ipcp_options peer_opts = ipcp_hisoptions[0];
GHashTable *hash;
GArray *array;
GValue *val;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_message ("nm-l2tp-ppp-plugin: (%s): ip-up event", __func__);
if (!opts.ouraddr) {
g_warning ("nm-l2tp-ppp-plugin: (%s): didn't receive an internal IP from pppd!", __func__);
return;
}
hash = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, value_destroy);
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV,
str_to_gvalue (ifname));
/* Prefer the peer options remote address first, _unless_ pppd made the
* address up, at which point prefer the local options remote address,
* and if that's not right, use the made-up address as a last resort.
*/
if (peer_opts.hisaddr && (peer_opts.hisaddr != pppd_made_up_address)) {
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
uint_to_gvalue (peer_opts.hisaddr));
} else if (opts.hisaddr) {
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
uint_to_gvalue (opts.hisaddr));
} else if (peer_opts.hisaddr == pppd_made_up_address) {
/* As a last resort, use the made-up address */
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP,
uint_to_gvalue (peer_opts.hisaddr));
}
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
uint_to_gvalue (opts.ouraddr));
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, uint_to_gvalue (32));
if (opts.dnsaddr[0] || opts.dnsaddr[1]) {
array = g_array_new (FALSE, FALSE, sizeof (guint32));
if (opts.dnsaddr[0])
g_array_append_val (array, opts.dnsaddr[0]);
if (opts.dnsaddr[1])
g_array_append_val (array, opts.dnsaddr[1]);
val = g_slice_new0 (GValue);
g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
g_value_set_boxed (val, array);
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
}
/* Default MTU to 1400, which is also what Windows XP/Vista use */
g_hash_table_insert (hash, NM_VPN_PLUGIN_IP4_CONFIG_MTU, uint_to_gvalue (1400));
g_message ("nm-l2tp-ppp-plugin: (%s): sending Ip4Config to NetworkManager-l2tp...", __func__);
dbus_g_proxy_call_no_reply (proxy, "SetIp4Config",
DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID,
G_TYPE_INVALID);
g_hash_table_destroy (hash);
}
static int
get_chap_check()
{
return 1;
}
static int
get_pap_check()
{
return 1;
}
static int
get_credentials (char *username, char *password)
{
char *my_username = NULL;
char *my_password = NULL;
size_t len;
GError *err = NULL;
if (username && !password) {
/* pppd is checking pap support; return 1 for supported */
return 1;
}
g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), -1);
g_message ("nm-l2tp-ppp-plugin: (%s): passwd-hook, requesting credentials...", __func__);
dbus_g_proxy_call (proxy, "NeedSecrets", &err,
G_TYPE_INVALID,
G_TYPE_STRING, &my_username,
G_TYPE_STRING, &my_password,
G_TYPE_INVALID);
if (err) {
g_warning ("nm-l2tp-ppp-plugin: (%s): could not get secrets: (%d) %s",
__func__,
err ? err->code : -1,
err->message ? err->message : "(unknown)");
g_error_free (err);
return -1;
}
g_message ("nm-l2tp-ppp-plugin: (%s): got credentials from NetworkManager-l2tp", __func__);
if (my_username) {
len = strlen (my_username) + 1;
len = len < MAXNAMELEN ? len : MAXNAMELEN;
strncpy (username, my_username, len);
username[len - 1] = '\0';
g_free (my_username);
}
if (my_password) {
len = strlen (my_password) + 1;
len = len < MAXSECRETLEN ? len : MAXSECRETLEN;
strncpy (password, my_password, len);
password[len - 1] = '\0';
g_free (my_password);
}
return 1;
}
static void
nm_exit_notify (void *data, int arg)
{
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_message ("nm-l2tp-ppp-plugin: (%s): cleaning up", __func__);
g_object_unref (proxy);
proxy = NULL;
}
int
plugin_init (void)
{
DBusGConnection *bus;
GError *err = NULL;
g_type_init ();
g_message ("nm-l2tp-ppp-plugin: (%s): initializing", __func__);
bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
if (!bus) {
g_warning ("nm-l2tp-pppd-plugin: (%s): couldn't connect to system bus: (%d) %s",
__func__,
err ? err->code : -1,
err && err->message ? err->message : "(unknown)");
g_error_free (err);
return -1;
}
proxy = dbus_g_proxy_new_for_name (bus,
NM_DBUS_SERVICE_L2TP_PPP,
NM_DBUS_PATH_L2TP_PPP,
NM_DBUS_INTERFACE_L2TP_PPP);
dbus_g_connection_unref (bus);
chap_passwd_hook = get_credentials;
chap_check_hook = get_chap_check;
pap_passwd_hook = get_credentials;
pap_check_hook = get_pap_check;
add_notifier (&phasechange, nm_phasechange, NULL);
add_notifier (&ip_up_notifier, nm_ip_up, NULL);
add_notifier (&exitnotify, nm_exit_notify, proxy);
return 0;
}
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/">
<interface name="org.freedesktop.NetworkManager.l2tp.ppp">
<method name="NeedSecrets">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_l2tp_service_need_secrets"/>
<arg name="username" type="s" direction="out"/>
<arg name="password" type="s" direction="out"/>
</method>
<method name="SetIp4Config">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_l2tp_service_set_ip4_config"/>
<arg name="config" type="a{sv}" direction="in"/>
</method>
<method name="SetState">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_l2tp_service_set_state"/>
<arg name="state" type="u" direction="in"/>
</method>
</interface>
</node>
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-l2tp-service - L2TP VPN integration with NetworkManager
*
* Dan Williams <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 - 2009 Red Hat, Inc.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <nm-setting-vpn.h>
#include <nm-utils.h>
#include "nm-l2tp-service.h"
#include "nm-ppp-status.h"
/********************************************************/
/* ppp plugin <-> l2tp-service object */
/********************************************************/
/* Have to have a separate objec to handle ppp plugin requests since
* dbus-glib doesn't allow multiple interfaces registed on one GObject.
*/
#define NM_TYPE_L2TP_PPP_SERVICE (nm_l2tp_ppp_service_get_type ())
#define NM_L2TP_PPP_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_L2TP_PPP_SERVICE, NML2tpPppService))
#define NM_L2TP_PPP_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_L2TP_PPP_SERVICE, NML2tpPppServiceClass))
#define NM_IS_L2TP_PPP_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_L2TP_PPP_SERVICE))
#define NM_IS_L2TP_PPP_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_L2TP_PPP_SERVICE))
#define NM_L2TP_PPP_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_L2TP_PPP_SERVICE, NML2tpPppServiceClass))
typedef struct {
GObject parent;
} NML2tpPppService;
typedef struct {
GObjectClass parent;
/* Signals */
void (*plugin_alive) (NML2tpPppService *self);
void (*ppp_state) (NML2tpPppService *self, guint32 state);
void (*ip4_config) (NML2tpPppService *self, GHashTable *config_hash);
} NML2tpPppServiceClass;
GType nm_l2tp_ppp_service_get_type (void);
G_DEFINE_TYPE (NML2tpPppService, nm_l2tp_ppp_service, G_TYPE_OBJECT)
static gboolean impl_l2tp_service_need_secrets (NML2tpPppService *self,
char **out_username,
char **out_password,
GError **err);
static gboolean impl_l2tp_service_set_state (NML2tpPppService *self,
guint32 state,
GError **err);
static gboolean impl_l2tp_service_set_ip4_config (NML2tpPppService *self,
GHashTable *config,
GError **err);
#include "nm-l2tp-pppd-service-glue.h"
#define NM_L2TP_PPP_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_L2TP_PPP_SERVICE, NML2tpPppServicePrivate))
typedef struct {
char username[100];
char domain[100];
char password[100];
} NML2tpPppServicePrivate;
enum {
PLUGIN_ALIVE,
PPP_STATE,
IP4_CONFIG,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static NML2tpPppService *
nm_l2tp_ppp_service_new (void)
{
DBusGConnection *connection;
DBusGProxy *proxy;
GError *error = NULL;
gboolean success = FALSE;
guint request_name_result;
GObject *object;
object = g_object_new (NM_TYPE_L2TP_PPP_SERVICE, NULL);
dbus_connection_set_change_sigpipe (TRUE);
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (!connection) {
nm_warning ("Could not get the system bus. Make sure "
"the message bus daemon is running! Message: %s",
error->message);
g_error_free (error);
g_object_unref (object);
return NULL;
}
proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
if (dbus_g_proxy_call (proxy, "RequestName", &error,
G_TYPE_STRING, NM_DBUS_SERVICE_L2TP_PPP,
G_TYPE_UINT, 0,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID)) {
dbus_g_connection_register_g_object (connection, NM_DBUS_PATH_L2TP_PPP, object);
success = TRUE;
} else {
nm_warning ("Could not register D-Bus service name. Message: %s", error->message);
g_error_free (error);
g_object_unref (object);
object = NULL;
}
g_object_unref (proxy);
return (NML2tpPppService *) object;
}
static void
nm_l2tp_ppp_service_init (NML2tpPppService *self)
{
}
static void
finalize (GObject *object)
{
NML2tpPppServicePrivate *priv = NM_L2TP_PPP_SERVICE_GET_PRIVATE (object);
/* Get rid of the cached username and password */
memset (priv->username, 0, sizeof (priv->username));
memset (priv->domain, 0, sizeof (priv->domain));
memset (priv->password, 0, sizeof (priv->password));
}
static void
nm_l2tp_ppp_service_class_init (NML2tpPppServiceClass *service_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (service_class);
g_type_class_add_private (service_class, sizeof (NML2tpPppServicePrivate));
/* virtual methods */
object_class->finalize = finalize;
/* Signals */
signals[PLUGIN_ALIVE] =
g_signal_new ("plugin-alive",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NML2tpPppServiceClass, plugin_alive),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[PPP_STATE] =
g_signal_new ("ppp-state",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NML2tpPppServiceClass, ppp_state),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[IP4_CONFIG] =
g_signal_new ("ip4-config",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NML2tpPppServiceClass, ip4_config),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (service_class),
&dbus_glib_nm_l2tp_pppd_service_object_info);
}
static gboolean
nm_l2tp_ppp_service_cache_credentials (NML2tpPppService *self,
NMConnection *connection,
GError **error)
{
NML2tpPppServicePrivate *priv = NM_L2TP_PPP_SERVICE_GET_PRIVATE (self);
NMSettingVPN *s_vpn;
const char *username, *password, *domain;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (connection != NULL, FALSE);
memset (priv->username, 0, sizeof (priv->username));
memset (priv->domain, 0, sizeof (priv->domain));
memset (priv->password, 0, sizeof (priv->password));
s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
if (!s_vpn) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"Could not find secrets (connection invalid, no vpn setting).");
return FALSE;
}
/* Username; try L2TP specific username first, then generic username */
username = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_USER);
if (username && strlen (username)) {
/* FIXME: This check makes about 0 sense. */
if (!username || !strlen (username)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"Invalid VPN username.");
return FALSE;
}
} else {
username = nm_setting_vpn_get_user_name (s_vpn);
if (!username || !strlen (username)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"Missing VPN username.");
return FALSE;
}
}
password = nm_setting_vpn_get_secret (s_vpn, NM_L2TP_KEY_PASSWORD);
if (!password || !strlen (password)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"Missing or invalid VPN password.");
return FALSE;
}
domain = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_DOMAIN);
if (domain && strlen (domain))
memcpy (priv->domain, domain, strlen (domain));
memcpy (priv->username, username, strlen (username));
memcpy (priv->password, password, strlen (password));
return TRUE;
}
static gboolean
impl_l2tp_service_need_secrets (NML2tpPppService *self,
char **out_username,
char **out_password,
GError **error)
{
NML2tpPppServicePrivate *priv = NM_L2TP_PPP_SERVICE_GET_PRIVATE (self);
g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
if (!strlen (priv->username) || !strlen (priv->password)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"No cached credentials.");
goto error;
}
/* Success */
if (strlen (priv->domain))
*out_username = g_strdup_printf ("%s\\%s", priv->domain, priv->username);
else
*out_username = g_strdup (priv->username);
*out_password = g_strdup (priv->password);
return TRUE;
error:
return FALSE;
}
static gboolean
impl_l2tp_service_set_state (NML2tpPppService *self,
guint32 pppd_state,
GError **err)
{
g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
g_signal_emit (G_OBJECT (self), signals[PPP_STATE], 0, pppd_state);
return TRUE;
}
static gboolean
impl_l2tp_service_set_ip4_config (NML2tpPppService *self,
GHashTable *config_hash,
GError **err)
{
nm_info ("L2TP service (IP Config Get) reply received.");
g_signal_emit (G_OBJECT (self), signals[PLUGIN_ALIVE], 0);
/* Just forward the pppd plugin config up to our superclass; no need to modify it */
g_signal_emit (G_OBJECT (self), signals[IP4_CONFIG], 0, config_hash);
return TRUE;
}
/********************************************************/
/* The VPN plugin service */
/********************************************************/
G_DEFINE_TYPE (NML2tpPlugin, nm_l2tp_plugin, NM_TYPE_VPN_PLUGIN)
typedef struct {
GPid pid;
guint32 ppp_timeout_handler;
NML2tpPppService *service;
NMConnection *connection;
} NML2tpPluginPrivate;
#define NM_L2TP_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_L2TP_PLUGIN, NML2tpPluginPrivate))
#define NM_L2TP_PPPD_PLUGIN PLUGINDIR "/nm-l2tp-pppd-plugin.so"
#define NM_L2TP_WAIT_PPPD 10000 /* 10 seconds */
#define L2TP_SERVICE_SECRET_TRIES "l2tp-service-secret-tries"
typedef struct {
const char *name;
GType type;
gboolean required;
} ValidProperty;
static ValidProperty valid_properties[] = {
{ NM_L2TP_KEY_GATEWAY, G_TYPE_STRING, TRUE },
{ NM_L2TP_KEY_USER, G_TYPE_STRING, FALSE },
{ NM_L2TP_KEY_DOMAIN, G_TYPE_STRING, FALSE },
{ NM_L2TP_KEY_REFUSE_EAP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REFUSE_PAP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REFUSE_CHAP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REFUSE_MSCHAP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REFUSE_MSCHAPV2, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REQUIRE_MPPE, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REQUIRE_MPPE_40, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_REQUIRE_MPPE_128, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_MPPE_STATEFUL, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_NOBSDCOMP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_NODEFLATE, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_NO_VJ_COMP, G_TYPE_BOOLEAN, FALSE },
{ NM_L2TP_KEY_LCP_ECHO_FAILURE, G_TYPE_UINT, FALSE },
{ NM_L2TP_KEY_LCP_ECHO_INTERVAL, G_TYPE_UINT, FALSE },
{ NULL, G_TYPE_NONE, FALSE }
};
static ValidProperty valid_secrets[] = {
{ NM_L2TP_KEY_PASSWORD, G_TYPE_STRING, FALSE },
{ NULL, G_TYPE_NONE, FALSE }
};
static gboolean
validate_gateway (const char *gateway)
{
const char *p = gateway;
if (!gateway || !strlen (gateway))
return FALSE;
/* Ensure it's a valid DNS name or IP address */
p = gateway;
while (*p) {
if (!isalnum (*p) && (*p != '-') && (*p != '.'))
return FALSE;
p++;
}
return TRUE;
}
typedef struct ValidateInfo {
ValidProperty *table;
GError **error;
gboolean have_items;
} ValidateInfo;
static void
validate_one_property (const char *key, const char *value, gpointer user_data)
{
ValidateInfo *info = (ValidateInfo *) user_data;
int i;
if (*(info->error))
return;
info->have_items = TRUE;
/* 'name' is the setting name; always allowed but unused */
if (!strcmp (key, NM_SETTING_NAME))
return;
for (i = 0; info->table[i].name; i++) {
ValidProperty prop = info->table[i];
long int tmp;
if (strcmp (prop.name, key))
continue;
switch (prop.type) {
case G_TYPE_STRING:
if ( !strcmp (prop.name, NM_L2TP_KEY_GATEWAY)
&& !validate_gateway (value)) {
g_set_error (info->error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"invalid gateway '%s'",
key);
return;
}
return; /* valid */
case G_TYPE_UINT:
errno = 0;
tmp = strtol (value, NULL, 10);
if (errno == 0)
return; /* valid */
g_set_error (info->error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"invalid integer property '%s'",
key);
break;
case G_TYPE_BOOLEAN:
if (!strcmp (value, "yes") || !strcmp (value, "no"))
return; /* valid */
g_set_error (info->error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"invalid boolean property '%s' (not yes or no)",
key);
break;
default:
g_set_error (info->error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"unhandled property '%s' type %s",
key, g_type_name (prop.type));
break;
}
}
/* Did not find the property from valid_properties or the type did not match */
if (!info->table[i].name) {
g_set_error (info->error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"property '%s' invalid or not supported",
key);
}
}
static gboolean
nm_l2tp_properties_validate (NMSettingVPN *s_vpn,
GError **error)
{
ValidateInfo info = { &valid_properties[0], error, FALSE };
int i;
nm_setting_vpn_foreach_data_item (s_vpn, validate_one_property, &info);
if (!info.have_items) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"%s",
"No VPN configuration options.");
return FALSE;
}
if (*error)
return FALSE;
/* Ensure required properties exist */
for (i = 0; valid_properties[i].name; i++) {
ValidProperty prop = valid_properties[i];
const char *value;
if (!prop.required)
continue;
value = nm_setting_vpn_get_data_item (s_vpn, prop.name);
if (!value || !strlen (value)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"Missing required option '%s'.",
prop.name);
return FALSE;
}
}
return TRUE;
}
static gboolean
nm_l2tp_secrets_validate (NMSettingVPN *s_vpn, GError **error)
{
ValidateInfo info = { &valid_secrets[0], error, FALSE };
nm_setting_vpn_foreach_secret (s_vpn, validate_one_property, &info);
if (!info.have_items) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"%s",
"No VPN secrets!");
return FALSE;
}
return *error ? FALSE : TRUE;
}
static void
pppd_watch_cb (GPid pid, gint status, gpointer user_data)
{
NML2tpPlugin *plugin = NM_L2TP_PLUGIN (user_data);
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
guint error = 0;
if (WIFEXITED (status)) {
error = WEXITSTATUS (status);
if (error != 0)
nm_warning ("pppd exited with error code %d", error);
}
else if (WIFSTOPPED (status))
nm_warning ("pppd stopped unexpectedly with signal %d", WSTOPSIG (status));
else if (WIFSIGNALED (status))
nm_warning ("pppd died with signal %d", WTERMSIG (status));
else
nm_warning ("pppd died from an unknown cause");
/* Reap child if needed. */
waitpid (priv->pid, NULL, WNOHANG);
priv->pid = 0;
/* Must be after data->state is set since signals use data->state */
switch (error) {
case 16:
/* hangup */
// FIXME: better failure reason
nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
break;
case 2:
/* Couldn't log in due to bad user/pass */
nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
break;
case 1:
/* Other error (couldn't bind to address, etc) */
nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
break;
default:
break;
}
nm_vpn_plugin_set_state (NM_VPN_PLUGIN (plugin), NM_VPN_SERVICE_STATE_STOPPED);
}
static inline const char *
nm_find_pppd (void)
{
static const char *pppd_binary_paths[] =
{
"/sbin/pppd",
"/usr/sbin/pppd",
"/usr/local/sbin/pppd",
NULL
};
const char **pppd_binary = pppd_binary_paths;
while (*pppd_binary != NULL) {
if (g_file_test (*pppd_binary, G_FILE_TEST_EXISTS))
break;
pppd_binary++;
}
return *pppd_binary;
}
static inline const char *
nm_find_l2tp (void)
{
static const char *l2tp_binary_paths[] =
{
"/sbin/l2tp",
"/usr/sbin/l2tp",
"/usr/local/sbin/l2tp",
NULL
};
const char **l2tp_binary = l2tp_binary_paths;
while (*l2tp_binary != NULL) {
if (g_file_test (*l2tp_binary, G_FILE_TEST_EXISTS))
break;
l2tp_binary++;
}
return *l2tp_binary;
}
static gboolean
pppd_timed_out (gpointer user_data)
{
NML2tpPlugin *plugin = NM_L2TP_PLUGIN (user_data);
nm_warning ("Looks like pppd didn't initialize our dbus module");
nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT);
return FALSE;
}
static void
free_pppd_args (GPtrArray *args)
{
int i;
if (!args)
return;
for (i = 0; i < args->len; i++)
g_free (g_ptr_array_index (args, i));
g_ptr_array_free (args, TRUE);
}
static GPtrArray *
construct_pppd_args (NML2tpPlugin *plugin,
NMSettingVPN *s_vpn,
const char *pppd,
GError **error)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
NML2tpPppServicePrivate *service_priv = NULL;
GPtrArray *args = NULL;
const char *value, *l2tp_binary;
char *ipparam, *tmp;
const char *loglevel0 = "--loglevel 0";
const char *loglevel2 = "--loglevel 2";
l2tp_binary = nm_find_l2tp ();
if (!l2tp_binary) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
"%s",
"Could not find l2tp client binary.");
return FALSE;
}
args = g_ptr_array_new ();
g_ptr_array_add (args, (gpointer) g_strdup (pppd));
/* L2TP options */
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_GATEWAY);
if (!value || !strlen (value)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
"%s",
"Missing VPN gateway.");
goto error;
}
ipparam = g_strdup_printf ("nm-l2tp-service-%d", getpid ());
g_ptr_array_add (args, (gpointer) g_strdup ("pty"));
tmp = g_strdup_printf ("%s %s --nolaunchpppd %s --logstring %s",
l2tp_binary, value,
getenv ("NM_L2TP_DEBUG") ? loglevel2 : loglevel0,
ipparam);
g_ptr_array_add (args, (gpointer) tmp);
if (getenv ("NM_PPP_DEBUG"))
g_ptr_array_add (args, (gpointer) g_strdup ("debug"));
/* PPP options */
g_ptr_array_add (args, (gpointer) g_strdup ("ipparam"));
g_ptr_array_add (args, (gpointer) ipparam);
g_ptr_array_add (args, (gpointer) g_strdup ("nodetach"));
g_ptr_array_add (args, (gpointer) g_strdup ("lock"));
g_ptr_array_add (args, (gpointer) g_strdup ("usepeerdns"));
g_ptr_array_add (args, (gpointer) g_strdup ("noipdefault"));
g_ptr_array_add (args, (gpointer) g_strdup ("nodefaultroute"));
/* Don't need to auth the L2TP server */
g_ptr_array_add (args, (gpointer) g_strdup ("noauth"));
if (priv->service)
service_priv = NM_L2TP_PPP_SERVICE_GET_PRIVATE (priv->service);
if (service_priv && strlen (service_priv->username)) {
g_ptr_array_add (args, (gpointer) g_strdup ("user"));
g_ptr_array_add (args, (gpointer) g_strdup (service_priv->username));
}
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REFUSE_EAP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("refuse-eap"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REFUSE_PAP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("refuse-pap"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REFUSE_CHAP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("refuse-chap"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REFUSE_MSCHAP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("refuse-mschap"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REFUSE_MSCHAPV2);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("refuse-mschap-v2"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REQUIRE_MPPE);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REQUIRE_MPPE_40);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe-40"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_REQUIRE_MPPE_128);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("require-mppe-128"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_MPPE_STATEFUL);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("mppe-stateful"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_NOBSDCOMP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("nobsdcomp"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_NODEFLATE);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("nodeflate"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_NO_VJ_COMP);
if (value && !strcmp (value, "yes"))
g_ptr_array_add (args, (gpointer) g_strdup ("novj"));
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_LCP_ECHO_FAILURE);
if (value && strlen (value)) {
long int tmp_int;
/* Convert to integer and then back to string for security's sake
* because strtol ignores some leading and trailing characters.
*/
errno = 0;
tmp_int = strtol (value, NULL, 10);
if (errno == 0) {
g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-failure"));
g_ptr_array_add (args, (gpointer) g_strdup_printf ("%ld", tmp_int));
} else {
nm_warning ("failed to convert lcp-echo-failure value '%s'", value);
}
} else {
g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-failure"));
g_ptr_array_add (args, (gpointer) g_strdup ("0"));
}
value = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_LCP_ECHO_INTERVAL);
if (value && strlen (value)) {
long int tmp_int;
/* Convert to integer and then back to string for security's sake
* because strtol ignores some leading and trailing characters.
*/
errno = 0;
tmp_int = strtol (value, NULL, 10);
if (errno == 0) {
g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-interval"));
g_ptr_array_add (args, (gpointer) g_strdup_printf ("%ld", tmp_int));
} else {
nm_warning ("failed to convert lcp-echo-interval value '%s'", value);
}
} else {
g_ptr_array_add (args, (gpointer) g_strdup ("lcp-echo-interval"));
g_ptr_array_add (args, (gpointer) g_strdup ("0"));
}
g_ptr_array_add (args, (gpointer) g_strdup ("plugin"));
g_ptr_array_add (args, (gpointer) g_strdup (NM_L2TP_PPPD_PLUGIN));
g_ptr_array_add (args, NULL);
return args;
error:
free_pppd_args (args);
return FALSE;
}
static gboolean
nm_l2tp_start_pppd_binary (NML2tpPlugin *plugin,
NMSettingVPN *s_vpn,
GError **error)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
GPid pid;
const char *pppd_binary;
GPtrArray *pppd_argv;
pppd_binary = nm_find_pppd ();
if (!pppd_binary) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
"%s",
"Could not find the pppd binary.");
return FALSE;
}
pppd_argv = construct_pppd_args (plugin, s_vpn, pppd_binary, error);
if (!pppd_argv)
return FALSE;
if (!g_spawn_async (NULL, (char **) pppd_argv->pdata, NULL,
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, error)) {
g_ptr_array_free (pppd_argv, TRUE);
return FALSE;
}
free_pppd_args (pppd_argv);
nm_info ("pppd started with pid %d", pid);
NM_L2TP_PLUGIN_GET_PRIVATE (plugin)->pid = pid;
g_child_watch_add (pid, pppd_watch_cb, plugin);
priv->ppp_timeout_handler = g_timeout_add (NM_L2TP_WAIT_PPPD, pppd_timed_out, plugin);
return TRUE;
}
static void
remove_timeout_handler (NML2tpPlugin *plugin)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
if (priv->ppp_timeout_handler) {
g_source_remove (priv->ppp_timeout_handler);
priv->ppp_timeout_handler = 0;
}
}
static void
service_plugin_alive_cb (NML2tpPppService *service,
NML2tpPlugin *plugin)
{
remove_timeout_handler (plugin);
}
static void
service_ppp_state_cb (NML2tpPppService *service,
guint32 ppp_state,
NML2tpPlugin *plugin)
{
NMVPNServiceState plugin_state = nm_vpn_plugin_get_state (NM_VPN_PLUGIN (plugin));
switch (ppp_state) {
case NM_PPP_STATUS_DEAD:
case NM_PPP_STATUS_DISCONNECT:
if (plugin_state == NM_VPN_SERVICE_STATE_STARTED)
nm_vpn_plugin_disconnect (NM_VPN_PLUGIN (plugin), NULL);
else if (plugin_state == NM_VPN_SERVICE_STATE_STARTING)
nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
break;
default:
break;
}
}
static void
nm_gvalue_destroy (gpointer data)
{
g_value_unset ((GValue *) data);
g_slice_free (GValue, data);
}
static GValue *
nm_gvalue_dup (const GValue *value)
{
GValue *value_dup;
value_dup = g_slice_new0 (GValue);
g_value_init (value_dup, G_VALUE_TYPE (value));
g_value_copy (value, value_dup);
return value_dup;
}
static void
copy_hash (gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), nm_gvalue_dup ((GValue *) value));
}
static GValue *
get_l2tp_gw_address_as_gvalue (NMConnection *connection)
{
NMSettingVPN *s_vpn;
const char *tmp, *p;
GValue *value = NULL;
struct in_addr addr;
gboolean is_name = FALSE;
s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
if (!s_vpn) {
nm_warning ("couldn't get VPN setting");
return NULL;
}
p = tmp = nm_setting_vpn_get_data_item (s_vpn, NM_L2TP_KEY_GATEWAY);
if (!tmp || !strlen (tmp)) {
nm_warning ("couldn't get L2TP VPN gateway IP address");
return NULL;
}
while (*p) {
if (*p != '.' && !isdigit (*p)) {
is_name = TRUE;
break;
}
p++;
}
/* Resolve a hostname if required */
if (is_name) {
struct addrinfo hints;
struct addrinfo *result = NULL, *rp;
int err;
memset (&hints, 0, sizeof (hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG;
err = getaddrinfo (tmp, NULL, &hints, &result);
if (err != 0) {
nm_warning ("couldn't look up L2TP VPN gateway IP address '%s' (%d)", tmp, err);
return NULL;
}
/* FIXME: so what if the name resolves to multiple IP addresses? We
* don't know which one l2tp decided to use so we could end up using a
* different one here, and the VPN just won't work.
*/
for (rp = result; rp; rp = rp->ai_next) {
if ( (rp->ai_family == AF_INET)
&& (rp->ai_addrlen == sizeof (struct sockaddr_in))) {
struct sockaddr_in *inptr = (struct sockaddr_in *) rp->ai_addr;
memcpy (&addr, &(inptr->sin_addr), sizeof (struct in_addr));
break;
}
}
freeaddrinfo (result);
} else {
errno = 0;
if (inet_pton (AF_INET, tmp, &addr) <= 0) {
nm_warning ("couldn't convert L2TP VPN gateway IP address '%s' (%d)", tmp, errno);
return NULL;
}
}
if (addr.s_addr != 0) {
value = g_slice_new0 (GValue);
g_value_init (value, G_TYPE_UINT);
g_value_set_uint (value, (guint32) addr.s_addr);
} else
nm_warning ("couldn't determine L2TP VPN gateway IP address from '%s'", tmp);
return value;
}
static void
service_ip4_config_cb (NML2tpPppService *service,
GHashTable *config_hash,
NML2tpPlugin *plugin)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
GHashTable *hash;
GValue *value;
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy);
g_hash_table_foreach (config_hash, copy_hash, hash);
/* Insert the external VPN gateway into the table, which the pppd plugin
* simply doesn't know about.
*/
value = get_l2tp_gw_address_as_gvalue (priv->connection);
if (value)
g_hash_table_insert (hash, g_strdup (NM_L2TP_KEY_GATEWAY), value);
nm_vpn_plugin_set_ip4_config (NM_VPN_PLUGIN (plugin), hash);
g_hash_table_destroy (hash);
}
static gboolean
real_connect (NMVPNPlugin *plugin,
NMConnection *connection,
GError **error)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
NMSettingVPN *s_vpn;
s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
g_assert (s_vpn);
if (!nm_l2tp_properties_validate (s_vpn, error))
return FALSE;
if (!nm_l2tp_secrets_validate (s_vpn, error))
return FALSE;
/* Start our pppd plugin helper service */
if (priv->service)
g_object_unref (priv->service);
if (priv->connection) {
g_object_unref (priv->connection);
priv->connection = NULL;
}
priv->service = nm_l2tp_ppp_service_new ();
if (!priv->service) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
"%s",
"Could not start pppd plugin helper service.");
return FALSE;
}
priv->connection = g_object_ref (connection);
g_signal_connect (G_OBJECT (priv->service), "plugin-alive", G_CALLBACK (service_plugin_alive_cb), plugin);
g_signal_connect (G_OBJECT (priv->service), "ppp-state", G_CALLBACK (service_ppp_state_cb), plugin);
g_signal_connect (G_OBJECT (priv->service), "ip4-config", G_CALLBACK (service_ip4_config_cb), plugin);
/* Cache the username and password so we can relay the secrets to the pppd
* plugin when it asks for them.
*/
if (!nm_l2tp_ppp_service_cache_credentials (priv->service, connection, error))
return FALSE;
if (!nm_l2tp_start_pppd_binary (NM_L2TP_PLUGIN (plugin), s_vpn, error))
return FALSE;
return TRUE;
}
static gboolean
real_need_secrets (NMVPNPlugin *plugin,
NMConnection *connection,
char **setting_name,
GError **error)
{
NMSettingVPN *s_vpn;
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
if (!nm_setting_vpn_get_secret (s_vpn, NM_L2TP_KEY_PASSWORD)) {
*setting_name = NM_SETTING_VPN_SETTING_NAME;
return TRUE;
}
return FALSE;
}
static gboolean
ensure_killed (gpointer data)
{
int pid = GPOINTER_TO_INT (data);
if (kill (pid, 0) == 0)
kill (pid, SIGKILL);
return FALSE;
}
static gboolean
real_disconnect (NMVPNPlugin *plugin,
GError **err)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (plugin);
if (priv->pid) {
if (kill (priv->pid, SIGTERM) == 0)
g_timeout_add (2000, ensure_killed, GINT_TO_POINTER (priv->pid));
else
kill (priv->pid, SIGKILL);
nm_info ("Terminated ppp daemon with PID %d.", priv->pid);
priv->pid = 0;
}
if (priv->connection) {
g_object_unref (priv->connection);
priv->connection = NULL;
}
if (priv->service) {
g_object_unref (priv->service);
priv->service = NULL;
}
return TRUE;
}
static void
state_changed_cb (GObject *object, NMVPNServiceState state, gpointer user_data)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (object);
switch (state) {
case NM_VPN_SERVICE_STATE_STARTED:
remove_timeout_handler (NM_L2TP_PLUGIN (object));
break;
case NM_VPN_SERVICE_STATE_UNKNOWN:
case NM_VPN_SERVICE_STATE_INIT:
case NM_VPN_SERVICE_STATE_SHUTDOWN:
case NM_VPN_SERVICE_STATE_STOPPING:
case NM_VPN_SERVICE_STATE_STOPPED:
remove_timeout_handler (NM_L2TP_PLUGIN (object));
if (priv->connection) {
g_object_unref (priv->connection);
priv->connection = NULL;
}
if (priv->service) {
g_object_unref (priv->service);
priv->service = NULL;
}
break;
default:
break;
}
}
static void
dispose (GObject *object)
{
NML2tpPluginPrivate *priv = NM_L2TP_PLUGIN_GET_PRIVATE (object);
if (priv->connection)
g_object_unref (priv->connection);
if (priv->service)
g_object_unref (priv->service);
G_OBJECT_CLASS (nm_l2tp_plugin_parent_class)->dispose (object);
}
static void
nm_l2tp_plugin_init (NML2tpPlugin *plugin)
{
}
static void
nm_l2tp_plugin_class_init (NML2tpPluginClass *l2tp_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (l2tp_class);
NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS (l2tp_class);
g_type_class_add_private (object_class, sizeof (NML2tpPluginPrivate));
/* virtual methods */
object_class->dispose = dispose;
parent_class->connect = real_connect;
parent_class->need_secrets = real_need_secrets;
parent_class->disconnect = real_disconnect;
}
NML2tpPlugin *
nm_l2tp_plugin_new (void)
{
NML2tpPlugin *plugin;
plugin = g_object_new (NM_TYPE_L2TP_PLUGIN,
NM_VPN_PLUGIN_DBUS_SERVICE_NAME,
NM_DBUS_SERVICE_L2TP,
NULL);
if (plugin)
g_signal_connect (G_OBJECT (plugin), "state-changed", G_CALLBACK (state_changed_cb), NULL);
return plugin;
}
static void
quit_mainloop (NML2tpPlugin *plugin, gpointer user_data)
{
g_main_loop_quit ((GMainLoop *) user_data);
}
int
main (int argc, char *argv[])
{
NML2tpPlugin *plugin;
GMainLoop *main_loop;
g_type_init ();
plugin = nm_l2tp_plugin_new ();
if (!plugin)
exit (EXIT_FAILURE);
main_loop = g_main_loop_new (NULL, FALSE);
g_signal_connect (plugin, "quit",
G_CALLBACK (quit_mainloop),
main_loop);
g_main_loop_run (main_loop);
g_main_loop_unref (main_loop);
g_object_unref (plugin);
exit (EXIT_SUCCESS);
}
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-l2tp-service - L2TP VPN integration with NetworkManager
*
* Dan Williams <dcbw@redhat.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Red Hat, Inc.
*/
#ifndef NM_L2TP_PLUGIN_H
#define NM_L2TP_PLUGIN_H
#include <glib.h>
#include <glib-object.h>
#include <nm-vpn-plugin.h>
#define NM_TYPE_L2TP_PLUGIN (nm_l2tp_plugin_get_type ())
#define NM_L2TP_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_L2TP_PLUGIN, NML2tpPlugin))
#define NM_L2TP_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_L2TP_PLUGIN, NML2tpPluginClass))
#define NM_IS_L2TP_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_L2TP_PLUGIN))
#define NM_IS_L2TP_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_L2TP_PLUGIN))
#define NM_L2TP_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_L2TP_PLUGIN, NML2tpPluginClass))
/* For the pppd plugin <-> VPN plugin service */
#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
#define NM_DBUS_SERVICE_L2TP_PPP "org.freedesktop.NetworkManager.l2tp-ppp"
#define NM_DBUS_PATH_L2TP_PPP "/org/freedesktop/NetworkManager/l2tp/ppp"
#define NM_DBUS_INTERFACE_L2TP_PPP "org.freedesktop.NetworkManager.l2tp.ppp"
/* For the NM <-> VPN plugin service */
#define NM_DBUS_SERVICE_L2TP "org.freedesktop.NetworkManager.l2tp"
#define NM_DBUS_INTERFACE_L2TP "org.freedesktop.NetworkManager.l2tp"
#define NM_DBUS_PATH_L2TP "/org/freedesktop/NetworkManager/l2tp"
#define NM_L2TP_KEY_GATEWAY "gateway"
#define NM_L2TP_KEY_USER "user"
#define NM_L2TP_KEY_PASSWORD "password"
#define NM_L2TP_KEY_DOMAIN "domain"
#define NM_L2TP_KEY_REFUSE_EAP "refuse-eap"
#define NM_L2TP_KEY_REFUSE_PAP "refuse-pap"
#define NM_L2TP_KEY_REFUSE_CHAP "refuse-chap"
#define NM_L2TP_KEY_REFUSE_MSCHAP "refuse-mschap"
#define NM_L2TP_KEY_REFUSE_MSCHAPV2 "refuse-mschapv2"
#define NM_L2TP_KEY_REQUIRE_MPPE "require-mppe"
#define NM_L2TP_KEY_REQUIRE_MPPE_40 "require-mppe-40"
#define NM_L2TP_KEY_REQUIRE_MPPE_128 "require-mppe-128"
#define NM_L2TP_KEY_MPPE_STATEFUL "mppe-stateful"
#define NM_L2TP_KEY_NOBSDCOMP "nobsdcomp"
#define NM_L2TP_KEY_NODEFLATE "nodeflate"
#define NM_L2TP_KEY_NO_VJ_COMP "no-vj-comp"
#define NM_L2TP_KEY_LCP_ECHO_FAILURE "lcp-echo-failure"
#define NM_L2TP_KEY_LCP_ECHO_INTERVAL "lcp-echo-interval"
typedef struct {
NMVPNPlugin parent;
} NML2tpPlugin;
typedef struct {
NMVPNPluginClass parent;
} NML2tpPluginClass;
GType nm_l2tp_plugin_get_type (void);
NML2tpPlugin *nm_l2tp_plugin_new (void);
#endif /* NM_L2TP_PLUGIN_H */
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-l2tp-service - L2TP VPN integration with NetworkManager
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
#ifndef NM_PPP_STATUS_H
#define NM_PPP_STATUS_H
typedef enum {
NM_PPP_STATUS_UNKNOWN,
NM_PPP_STATUS_DEAD,
NM_PPP_STATUS_INITIALIZE,
NM_PPP_STATUS_SERIALCONN,
NM_PPP_STATUS_DORMANT,
NM_PPP_STATUS_ESTABLISH,
NM_PPP_STATUS_AUTHENTICATE,
NM_PPP_STATUS_CALLBACK,
NM_PPP_STATUS_NETWORK,
NM_PPP_STATUS_RUNNING,
NM_PPP_STATUS_TERMINATE,
NM_PPP_STATUS_DISCONNECT,
NM_PPP_STATUS_HOLDOFF,
NM_PPP_STATUS_MASTER
} NMPPPStatus;
#endif /* NM_PPP_STATUS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment